blob: facfdb1fa71c5ece5c6f7d7f14acf17227ffefd1 [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 Peterson3847bccc2006-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:
1076 * e7320/e7520/e7525 + Xeon
1077 * i3100 + Xeon/Celeron
1078 * Sysbus parity not supported on:
1079 * i3100 + Pentium M/Celeron M/Core Duo/Core2 Duo
1080 */
1081static void e752x_init_sysbus_parity_mask(struct e752x_pvt *pvt)
1082{
1083 char *cpu_id = cpu_data(0).x86_model_id;
1084 struct pci_dev *dev = pvt->dev_d0f1;
1085 int enable = 1;
1086
1087 /* Allow module paramter override, else see if CPU supports parity */
1088 if (sysbus_parity != -1) {
1089 enable = sysbus_parity;
1090 } else if (cpu_id[0] &&
1091 ((strstr(cpu_id, "Pentium") && strstr(cpu_id, " M ")) ||
1092 (strstr(cpu_id, "Celeron") && strstr(cpu_id, " M ")) ||
1093 (strstr(cpu_id, "Core") && strstr(cpu_id, "Duo")))) {
1094 e752x_printk(KERN_INFO, "System Bus Parity not "
1095 "supported by CPU, disabling\n");
1096 enable = 0;
1097 }
1098
1099 if (enable)
1100 pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x0000);
1101 else
1102 pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x0309);
1103}
1104
Doug Thompson13189522006-06-30 01:56:08 -07001105static void e752x_init_error_reporting_regs(struct e752x_pvt *pvt)
1106{
1107 struct pci_dev *dev;
1108
1109 dev = pvt->dev_d0f1;
1110 /* Turn off error disable & SMI in case the BIOS turned it on */
Andrei Konovalov5135b792008-04-29 01:03:13 -07001111 if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) {
1112 pci_write_config_dword(dev, I3100_NSI_EMASK, 0);
1113 pci_write_config_dword(dev, I3100_NSI_SMICMD, 0);
1114 } else {
1115 pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00);
1116 pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00);
1117 }
Peter Tyser94ee1cf2008-04-29 01:03:15 -07001118
1119 e752x_init_sysbus_parity_mask(pvt);
1120
Doug Thompson13189522006-06-30 01:56:08 -07001121 pci_write_config_word(dev, E752X_SYSBUS_SMICMD, 0x00);
1122 pci_write_config_byte(dev, E752X_BUF_ERRMASK, 0x00);
1123 pci_write_config_byte(dev, E752X_BUF_SMICMD, 0x00);
1124 pci_write_config_byte(dev, E752X_DRAM_ERRMASK, 0x00);
1125 pci_write_config_byte(dev, E752X_DRAM_SMICMD, 0x00);
1126}
1127
1128static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
1129{
1130 u16 pci_data;
1131 u8 stat8;
1132 struct mem_ctl_info *mci;
1133 struct e752x_pvt *pvt;
1134 u16 ddrcsr;
Dave Jiang203333c2007-07-19 01:50:06 -07001135 int drc_chan; /* Number of channels 0=1chan,1=2chan */
Doug Thompson13189522006-06-30 01:56:08 -07001136 struct e752x_error_info discard;
1137
1138 debugf0("%s(): mci\n", __func__);
1139 debugf0("Starting Probe1\n");
1140
1141 /* check to see if device 0 function 1 is enabled; if it isn't, we
1142 * assume the BIOS has reserved it for a reason and is expecting
1143 * exclusive access, we take care not to violate that assumption and
1144 * fail the probe. */
1145 pci_read_config_byte(pdev, E752X_DEVPRES1, &stat8);
1146 if (!force_function_unhide && !(stat8 & (1 << 5))) {
1147 printk(KERN_INFO "Contact your BIOS vendor to see if the "
Douglas Thompson052dfb42007-07-19 01:50:13 -07001148 "E752x error registers can be safely un-hidden\n");
Aristeu Rozanskif9b5a5d2007-09-11 15:23:32 -07001149 return -ENODEV;
Doug Thompson13189522006-06-30 01:56:08 -07001150 }
1151 stat8 |= (1 << 5);
1152 pci_write_config_byte(pdev, E752X_DEVPRES1, stat8);
1153
1154 pci_read_config_word(pdev, E752X_DDRCSR, &ddrcsr);
1155 /* FIXME: should check >>12 or 0xf, true for all? */
1156 /* Dual channel = 1, Single channel = 0 */
1157 drc_chan = dual_channel_active(ddrcsr);
1158
Doug Thompsonb8f6f972007-07-19 01:50:26 -07001159 mci = edac_mc_alloc(sizeof(*pvt), E752X_NR_CSROWS, drc_chan + 1, 0);
Doug Thompson13189522006-06-30 01:56:08 -07001160
1161 if (mci == NULL) {
1162 return -ENOMEM;
1163 }
1164
1165 debugf3("%s(): init mci\n", __func__);
1166 mci->mtype_cap = MEM_FLAG_RDDR;
Andrei Konovalov5135b792008-04-29 01:03:13 -07001167 /* 3100 IMCH supports SECDEC only */
1168 mci->edac_ctl_cap = (dev_idx == I3100) ? EDAC_FLAG_SECDED :
1169 (EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_S4ECD4ED);
Doug Thompson13189522006-06-30 01:56:08 -07001170 /* FIXME - what if different memory types are in different csrows? */
1171 mci->mod_name = EDAC_MOD_STR;
1172 mci->mod_ver = E752X_REVISION;
1173 mci->dev = &pdev->dev;
1174
1175 debugf3("%s(): init pvt\n", __func__);
Dave Jiang203333c2007-07-19 01:50:06 -07001176 pvt = (struct e752x_pvt *)mci->pvt_info;
Doug Thompson13189522006-06-30 01:56:08 -07001177 pvt->dev_info = &e752x_devs[dev_idx];
1178 pvt->mc_symmetric = ((ddrcsr & 0x10) != 0);
1179
1180 if (e752x_get_devs(pdev, dev_idx, pvt)) {
1181 edac_mc_free(mci);
1182 return -ENODEV;
1183 }
1184
1185 debugf3("%s(): more mci init\n", __func__);
1186 mci->ctl_name = pvt->dev_info->ctl_name;
Dave Jiangc4192702007-07-19 01:49:47 -07001187 mci->dev_name = pci_name(pdev);
Doug Thompson13189522006-06-30 01:56:08 -07001188 mci->edac_check = e752x_check;
1189 mci->ctl_page_to_phys = ctl_page_to_phys;
1190
Mark Grondona7297c262007-07-19 01:50:23 -07001191 /* set the map type. 1 = normal, 0 = reversed
1192 * Must be set before e752x_init_csrows in case csrow mapping
1193 * is reversed.
1194 */
Doug Thompson13189522006-06-30 01:56:08 -07001195 pci_read_config_byte(pdev, E752X_DRM, &stat8);
1196 pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f));
Alan Cox806c35f2006-01-18 17:44:08 -08001197
Mark Grondona7297c262007-07-19 01:50:23 -07001198 e752x_init_csrows(mci, pdev, ddrcsr);
1199 e752x_init_mem_map_table(pdev, pvt);
1200
Andrei Konovalov5135b792008-04-29 01:03:13 -07001201 if (dev_idx == I3100)
1202 mci->edac_cap = EDAC_FLAG_SECDED; /* the only mode supported */
1203 else
1204 mci->edac_cap |= EDAC_FLAG_NONE;
Dave Peterson537fba22006-03-26 01:38:40 -08001205 debugf3("%s(): tolm, remapbase, remaplimit\n", __func__);
Dave Petersone7ecd892006-03-26 01:38:52 -08001206
Alan Cox806c35f2006-01-18 17:44:08 -08001207 /* load the top of low memory, remap base, and remap limit vars */
Doug Thompson37f04582006-06-30 01:56:07 -07001208 pci_read_config_word(pdev, E752X_TOLM, &pci_data);
Alan Cox806c35f2006-01-18 17:44:08 -08001209 pvt->tolm = ((u32) pci_data) << 4;
Doug Thompson37f04582006-06-30 01:56:07 -07001210 pci_read_config_word(pdev, E752X_REMAPBASE, &pci_data);
Alan Cox806c35f2006-01-18 17:44:08 -08001211 pvt->remapbase = ((u32) pci_data) << 14;
Doug Thompson37f04582006-06-30 01:56:07 -07001212 pci_read_config_word(pdev, E752X_REMAPLIMIT, &pci_data);
Alan Cox806c35f2006-01-18 17:44:08 -08001213 pvt->remaplimit = ((u32) pci_data) << 14;
Dave Peterson537fba22006-03-26 01:38:40 -08001214 e752x_printk(KERN_INFO,
Douglas Thompson052dfb42007-07-19 01:50:13 -07001215 "tolm = %x, remapbase = %x, remaplimit = %x\n",
1216 pvt->tolm, pvt->remapbase, pvt->remaplimit);
Alan Cox806c35f2006-01-18 17:44:08 -08001217
Doug Thompson2d7bbb92006-06-30 01:56:08 -07001218 /* Here we assume that we will never see multiple instances of this
1219 * type of memory controller. The ID is therefore hardcoded to 0.
1220 */
Doug Thompsonb8f6f972007-07-19 01:50:26 -07001221 if (edac_mc_add_mc(mci)) {
Dave Peterson537fba22006-03-26 01:38:40 -08001222 debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -08001223 goto fail;
1224 }
1225
Doug Thompson13189522006-06-30 01:56:08 -07001226 e752x_init_error_reporting_regs(pvt);
Dave Jiang203333c2007-07-19 01:50:06 -07001227 e752x_get_error_info(mci, &discard); /* clear other MCH errors */
Alan Cox806c35f2006-01-18 17:44:08 -08001228
Dave Jiang91b99042007-07-19 01:49:52 -07001229 /* allocating generic PCI control info */
1230 e752x_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
1231 if (!e752x_pci) {
1232 printk(KERN_WARNING
Douglas Thompson052dfb42007-07-19 01:50:13 -07001233 "%s(): Unable to create PCI control\n", __func__);
Dave Jiang91b99042007-07-19 01:49:52 -07001234 printk(KERN_WARNING
Douglas Thompson052dfb42007-07-19 01:50:13 -07001235 "%s(): PCI error report via EDAC not setup\n",
1236 __func__);
Dave Jiang91b99042007-07-19 01:49:52 -07001237 }
1238
Alan Cox806c35f2006-01-18 17:44:08 -08001239 /* get this far and it's successful */
Dave Peterson537fba22006-03-26 01:38:40 -08001240 debugf3("%s(): success\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -08001241 return 0;
1242
Douglas Thompson052dfb42007-07-19 01:50:13 -07001243fail:
Doug Thompson13189522006-06-30 01:56:08 -07001244 pci_dev_put(pvt->dev_d0f0);
1245 pci_dev_put(pvt->dev_d0f1);
1246 pci_dev_put(pvt->bridge_ck);
1247 edac_mc_free(mci);
Dave Petersone7ecd892006-03-26 01:38:52 -08001248
Doug Thompson13189522006-06-30 01:56:08 -07001249 return -ENODEV;
Alan Cox806c35f2006-01-18 17:44:08 -08001250}
1251
1252/* returns count (>= 0), or negative on error */
1253static int __devinit e752x_init_one(struct pci_dev *pdev,
Douglas Thompson052dfb42007-07-19 01:50:13 -07001254 const struct pci_device_id *ent)
Alan Cox806c35f2006-01-18 17:44:08 -08001255{
Dave Peterson537fba22006-03-26 01:38:40 -08001256 debugf0("%s()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -08001257
1258 /* wake up and enable device */
Dave Jiang203333c2007-07-19 01:50:06 -07001259 if (pci_enable_device(pdev) < 0)
Alan Cox806c35f2006-01-18 17:44:08 -08001260 return -EIO;
Dave Petersone7ecd892006-03-26 01:38:52 -08001261
Alan Cox806c35f2006-01-18 17:44:08 -08001262 return e752x_probe1(pdev, ent->driver_data);
1263}
1264
Alan Cox806c35f2006-01-18 17:44:08 -08001265static void __devexit e752x_remove_one(struct pci_dev *pdev)
1266{
1267 struct mem_ctl_info *mci;
1268 struct e752x_pvt *pvt;
1269
Dave Peterson537fba22006-03-26 01:38:40 -08001270 debugf0("%s()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -08001271
Dave Jiang91b99042007-07-19 01:49:52 -07001272 if (e752x_pci)
1273 edac_pci_release_generic_ctl(e752x_pci);
1274
Doug Thompson37f04582006-06-30 01:56:07 -07001275 if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
Alan Cox806c35f2006-01-18 17:44:08 -08001276 return;
1277
Dave Jiang203333c2007-07-19 01:50:06 -07001278 pvt = (struct e752x_pvt *)mci->pvt_info;
Alan Cox806c35f2006-01-18 17:44:08 -08001279 pci_dev_put(pvt->dev_d0f0);
1280 pci_dev_put(pvt->dev_d0f1);
1281 pci_dev_put(pvt->bridge_ck);
1282 edac_mc_free(mci);
1283}
1284
Alan Cox806c35f2006-01-18 17:44:08 -08001285static const struct pci_device_id e752x_pci_tbl[] __devinitdata = {
Dave Petersone7ecd892006-03-26 01:38:52 -08001286 {
Dave Jiang203333c2007-07-19 01:50:06 -07001287 PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
1288 E7520},
Dave Petersone7ecd892006-03-26 01:38:52 -08001289 {
Dave Jiang203333c2007-07-19 01:50:06 -07001290 PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
1291 E7525},
Dave Petersone7ecd892006-03-26 01:38:52 -08001292 {
Dave Jiang203333c2007-07-19 01:50:06 -07001293 PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
1294 E7320},
Dave Petersone7ecd892006-03-26 01:38:52 -08001295 {
Andrei Konovalov5135b792008-04-29 01:03:13 -07001296 PCI_VEND_DEV(INTEL, 3100_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
1297 I3100},
1298 {
Dave Jiang203333c2007-07-19 01:50:06 -07001299 0,
1300 } /* 0 terminated list. */
Alan Cox806c35f2006-01-18 17:44:08 -08001301};
1302
1303MODULE_DEVICE_TABLE(pci, e752x_pci_tbl);
1304
Alan Cox806c35f2006-01-18 17:44:08 -08001305static struct pci_driver e752x_driver = {
Dave Peterson680cbbb2006-03-26 01:38:41 -08001306 .name = EDAC_MOD_STR,
Randy Dunlap0d38b042006-02-03 03:04:24 -08001307 .probe = e752x_init_one,
1308 .remove = __devexit_p(e752x_remove_one),
1309 .id_table = e752x_pci_tbl,
Alan Cox806c35f2006-01-18 17:44:08 -08001310};
1311
Alan Coxda9bb1d2006-01-18 17:44:13 -08001312static int __init e752x_init(void)
Alan Cox806c35f2006-01-18 17:44:08 -08001313{
1314 int pci_rc;
1315
Dave Peterson537fba22006-03-26 01:38:40 -08001316 debugf3("%s()\n", __func__);
Hitoshi Mitakec3c52bc2008-04-29 01:03:18 -07001317
1318 /* Ensure that the OPSTATE is set correctly for POLL or NMI */
1319 opstate_init();
1320
Alan Cox806c35f2006-01-18 17:44:08 -08001321 pci_rc = pci_register_driver(&e752x_driver);
1322 return (pci_rc < 0) ? pci_rc : 0;
1323}
1324
Alan Cox806c35f2006-01-18 17:44:08 -08001325static void __exit e752x_exit(void)
1326{
Dave Peterson537fba22006-03-26 01:38:40 -08001327 debugf3("%s()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -08001328 pci_unregister_driver(&e752x_driver);
1329}
1330
Alan Cox806c35f2006-01-18 17:44:08 -08001331module_init(e752x_init);
1332module_exit(e752x_exit);
1333
1334MODULE_LICENSE("GPL");
1335MODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman\n");
Andrei Konovalov5135b792008-04-29 01:03:13 -07001336MODULE_DESCRIPTION("MC support for Intel e752x/3100 memory controllers");
mark gross96941022006-05-03 19:55:07 -07001337
1338module_param(force_function_unhide, int, 0444);
1339MODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:"
Doug Thompson10d33e92008-07-25 01:49:12 -07001340 " 1=force unhide and hope BIOS doesn't fight driver for "
1341 "Dev0:Fun1 access");
Hitoshi Mitakec3c52bc2008-04-29 01:03:18 -07001342
Dave Jiangc0d12172007-07-19 01:49:46 -07001343module_param(edac_op_state, int, 0444);
1344MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
Peter Tyser94ee1cf2008-04-29 01:03:15 -07001345
1346module_param(sysbus_parity, int, 0444);
1347MODULE_PARM_DESC(sysbus_parity, "0=disable system bus parity checking,"
1348 " 1=enable system bus parity checking, default=auto-detect");
Doug Thompson10d33e92008-07-25 01:49:12 -07001349module_param(report_non_memory_errors, int, 0644);
1350MODULE_PARM_DESC(report_non_memory_errors, "0=disable non-memory error "
1351 "reporting, 1=enable non-memory error reporting");