blob: 4fbc5892bc2b0e2a3b10a1f09c8f959c1e63a4b4 [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
mark gross96941022006-05-03 19:55:07 -070031static int force_function_unhide;
32
Dave Jiang91b99042007-07-19 01:49:52 -070033static struct edac_pci_ctl_info *e752x_pci;
34
Dave Peterson537fba22006-03-26 01:38:40 -080035#define e752x_printk(level, fmt, arg...) \
Dave Petersone7ecd892006-03-26 01:38:52 -080036 edac_printk(level, "e752x", fmt, ##arg)
Dave Peterson537fba22006-03-26 01:38:40 -080037
38#define e752x_mc_printk(mci, level, fmt, arg...) \
Dave Petersone7ecd892006-03-26 01:38:52 -080039 edac_mc_chipset_printk(mci, level, "e752x", fmt, ##arg)
Dave Peterson537fba22006-03-26 01:38:40 -080040
Alan Cox806c35f2006-01-18 17:44:08 -080041#ifndef PCI_DEVICE_ID_INTEL_7520_0
42#define PCI_DEVICE_ID_INTEL_7520_0 0x3590
43#endif /* PCI_DEVICE_ID_INTEL_7520_0 */
44
45#ifndef PCI_DEVICE_ID_INTEL_7520_1_ERR
46#define PCI_DEVICE_ID_INTEL_7520_1_ERR 0x3591
47#endif /* PCI_DEVICE_ID_INTEL_7520_1_ERR */
48
49#ifndef PCI_DEVICE_ID_INTEL_7525_0
50#define PCI_DEVICE_ID_INTEL_7525_0 0x359E
51#endif /* PCI_DEVICE_ID_INTEL_7525_0 */
52
53#ifndef PCI_DEVICE_ID_INTEL_7525_1_ERR
54#define PCI_DEVICE_ID_INTEL_7525_1_ERR 0x3593
55#endif /* PCI_DEVICE_ID_INTEL_7525_1_ERR */
56
57#ifndef PCI_DEVICE_ID_INTEL_7320_0
58#define PCI_DEVICE_ID_INTEL_7320_0 0x3592
59#endif /* PCI_DEVICE_ID_INTEL_7320_0 */
60
61#ifndef PCI_DEVICE_ID_INTEL_7320_1_ERR
62#define PCI_DEVICE_ID_INTEL_7320_1_ERR 0x3593
63#endif /* PCI_DEVICE_ID_INTEL_7320_1_ERR */
64
Andrei Konovalov5135b792008-04-29 01:03:13 -070065#ifndef PCI_DEVICE_ID_INTEL_3100_0
66#define PCI_DEVICE_ID_INTEL_3100_0 0x35B0
67#endif /* PCI_DEVICE_ID_INTEL_3100_0 */
68
69#ifndef PCI_DEVICE_ID_INTEL_3100_1_ERR
70#define PCI_DEVICE_ID_INTEL_3100_1_ERR 0x35B1
71#endif /* PCI_DEVICE_ID_INTEL_3100_1_ERR */
72
Alan Cox806c35f2006-01-18 17:44:08 -080073#define E752X_NR_CSROWS 8 /* number of csrows */
74
Alan Cox806c35f2006-01-18 17:44:08 -080075/* E752X register addresses - device 0 function 0 */
76#define E752X_DRB 0x60 /* DRAM row boundary register (8b) */
77#define E752X_DRA 0x70 /* DRAM row attribute register (8b) */
78 /*
79 * 31:30 Device width row 7
80 * 01=x8 10=x4 11=x8 DDR2
81 * 27:26 Device width row 6
82 * 23:22 Device width row 5
83 * 19:20 Device width row 4
84 * 15:14 Device width row 3
85 * 11:10 Device width row 2
86 * 7:6 Device width row 1
87 * 3:2 Device width row 0
88 */
89#define E752X_DRC 0x7C /* DRAM controller mode reg (32b) */
90 /* FIXME:IS THIS RIGHT? */
91 /*
92 * 22 Number channels 0=1,1=2
93 * 19:18 DRB Granularity 32/64MB
94 */
95#define E752X_DRM 0x80 /* Dimm mapping register */
96#define E752X_DDRCSR 0x9A /* DDR control and status reg (16b) */
97 /*
98 * 14:12 1 single A, 2 single B, 3 dual
99 */
100#define E752X_TOLM 0xC4 /* DRAM top of low memory reg (16b) */
101#define E752X_REMAPBASE 0xC6 /* DRAM remap base address reg (16b) */
102#define E752X_REMAPLIMIT 0xC8 /* DRAM remap limit address reg (16b) */
103#define E752X_REMAPOFFSET 0xCA /* DRAM remap limit offset reg (16b) */
104
105/* E752X register addresses - device 0 function 1 */
106#define E752X_FERR_GLOBAL 0x40 /* Global first error register (32b) */
107#define E752X_NERR_GLOBAL 0x44 /* Global next error register (32b) */
108#define E752X_HI_FERR 0x50 /* Hub interface first error reg (8b) */
109#define E752X_HI_NERR 0x52 /* Hub interface next error reg (8b) */
110#define E752X_HI_ERRMASK 0x54 /* Hub interface error mask reg (8b) */
111#define E752X_HI_SMICMD 0x5A /* Hub interface SMI command reg (8b) */
112#define E752X_SYSBUS_FERR 0x60 /* System buss first error reg (16b) */
113#define E752X_SYSBUS_NERR 0x62 /* System buss next error reg (16b) */
114#define E752X_SYSBUS_ERRMASK 0x64 /* System buss error mask reg (16b) */
115#define E752X_SYSBUS_SMICMD 0x6A /* System buss SMI command reg (16b) */
116#define E752X_BUF_FERR 0x70 /* Memory buffer first error reg (8b) */
117#define E752X_BUF_NERR 0x72 /* Memory buffer next error reg (8b) */
118#define E752X_BUF_ERRMASK 0x74 /* Memory buffer error mask reg (8b) */
119#define E752X_BUF_SMICMD 0x7A /* Memory buffer SMI command reg (8b) */
120#define E752X_DRAM_FERR 0x80 /* DRAM first error register (16b) */
121#define E752X_DRAM_NERR 0x82 /* DRAM next error register (16b) */
122#define E752X_DRAM_ERRMASK 0x84 /* DRAM error mask register (8b) */
123#define E752X_DRAM_SMICMD 0x8A /* DRAM SMI command register (8b) */
124#define E752X_DRAM_RETR_ADD 0xAC /* DRAM Retry address register (32b) */
125#define E752X_DRAM_SEC1_ADD 0xA0 /* DRAM first correctable memory */
126 /* error address register (32b) */
127 /*
128 * 31 Reserved
129 * 30:2 CE address (64 byte block 34:6)
130 * 1 Reserved
131 * 0 HiLoCS
132 */
133#define E752X_DRAM_SEC2_ADD 0xC8 /* DRAM first correctable memory */
134 /* error address register (32b) */
135 /*
136 * 31 Reserved
137 * 30:2 CE address (64 byte block 34:6)
138 * 1 Reserved
139 * 0 HiLoCS
140 */
141#define E752X_DRAM_DED_ADD 0xA4 /* DRAM first uncorrectable memory */
142 /* error address register (32b) */
143 /*
144 * 31 Reserved
145 * 30:2 CE address (64 byte block 34:6)
146 * 1 Reserved
147 * 0 HiLoCS
148 */
149#define E752X_DRAM_SCRB_ADD 0xA8 /* DRAM first uncorrectable scrub memory */
150 /* error address register (32b) */
151 /*
152 * 31 Reserved
153 * 30:2 CE address (64 byte block 34:6)
154 * 1 Reserved
155 * 0 HiLoCS
156 */
157#define E752X_DRAM_SEC1_SYNDROME 0xC4 /* DRAM first correctable memory */
158 /* error syndrome register (16b) */
159#define E752X_DRAM_SEC2_SYNDROME 0xC6 /* DRAM second correctable memory */
160 /* error syndrome register (16b) */
161#define E752X_DEVPRES1 0xF4 /* Device Present 1 register (8b) */
162
Andrei Konovalov5135b792008-04-29 01:03:13 -0700163/* 3100 IMCH specific register addresses - device 0 function 1 */
164#define I3100_NSI_FERR 0x48 /* NSI first error reg (32b) */
165#define I3100_NSI_NERR 0x4C /* NSI next error reg (32b) */
166#define I3100_NSI_SMICMD 0x54 /* NSI SMI command register (32b) */
167#define I3100_NSI_EMASK 0x90 /* NSI error mask register (32b) */
168
Alan Cox806c35f2006-01-18 17:44:08 -0800169/* ICH5R register addresses - device 30 function 0 */
170#define ICH5R_PCI_STAT 0x06 /* PCI status register (16b) */
171#define ICH5R_PCI_2ND_STAT 0x1E /* PCI status secondary reg (16b) */
172#define ICH5R_PCI_BRIDGE_CTL 0x3E /* PCI bridge control register (16b) */
173
174enum e752x_chips {
175 E7520 = 0,
176 E7525 = 1,
Andrei Konovalov5135b792008-04-29 01:03:13 -0700177 E7320 = 2,
178 I3100 = 3
Alan Cox806c35f2006-01-18 17:44:08 -0800179};
180
Alan Cox806c35f2006-01-18 17:44:08 -0800181struct e752x_pvt {
182 struct pci_dev *bridge_ck;
183 struct pci_dev *dev_d0f0;
184 struct pci_dev *dev_d0f1;
185 u32 tolm;
186 u32 remapbase;
187 u32 remaplimit;
188 int mc_symmetric;
189 u8 map[8];
190 int map_type;
191 const struct e752x_dev_info *dev_info;
192};
193
Alan Cox806c35f2006-01-18 17:44:08 -0800194struct e752x_dev_info {
195 u16 err_dev;
Dave Peterson3847bccc2006-03-26 01:38:42 -0800196 u16 ctl_dev;
Alan Cox806c35f2006-01-18 17:44:08 -0800197 const char *ctl_name;
198};
199
200struct e752x_error_info {
201 u32 ferr_global;
202 u32 nerr_global;
Andrei Konovalov5135b792008-04-29 01:03:13 -0700203 u32 nsi_ferr; /* 3100 only */
204 u32 nsi_nerr; /* 3100 only */
205 u8 hi_ferr; /* all but 3100 */
206 u8 hi_nerr; /* all but 3100 */
Alan Cox806c35f2006-01-18 17:44:08 -0800207 u16 sysbus_ferr;
208 u16 sysbus_nerr;
209 u8 buf_ferr;
210 u8 buf_nerr;
211 u16 dram_ferr;
212 u16 dram_nerr;
213 u32 dram_sec1_add;
214 u32 dram_sec2_add;
215 u16 dram_sec1_syndrome;
216 u16 dram_sec2_syndrome;
217 u32 dram_ded_add;
218 u32 dram_scrb_add;
219 u32 dram_retr_add;
220};
221
222static const struct e752x_dev_info e752x_devs[] = {
223 [E7520] = {
Douglas Thompson052dfb42007-07-19 01:50:13 -0700224 .err_dev = PCI_DEVICE_ID_INTEL_7520_1_ERR,
225 .ctl_dev = PCI_DEVICE_ID_INTEL_7520_0,
226 .ctl_name = "E7520"},
Alan Cox806c35f2006-01-18 17:44:08 -0800227 [E7525] = {
Douglas Thompson052dfb42007-07-19 01:50:13 -0700228 .err_dev = PCI_DEVICE_ID_INTEL_7525_1_ERR,
229 .ctl_dev = PCI_DEVICE_ID_INTEL_7525_0,
230 .ctl_name = "E7525"},
Alan Cox806c35f2006-01-18 17:44:08 -0800231 [E7320] = {
Douglas Thompson052dfb42007-07-19 01:50:13 -0700232 .err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR,
233 .ctl_dev = PCI_DEVICE_ID_INTEL_7320_0,
234 .ctl_name = "E7320"},
Andrei Konovalov5135b792008-04-29 01:03:13 -0700235 [I3100] = {
236 .err_dev = PCI_DEVICE_ID_INTEL_3100_1_ERR,
237 .ctl_dev = PCI_DEVICE_ID_INTEL_3100_0,
238 .ctl_name = "3100"},
Alan Cox806c35f2006-01-18 17:44:08 -0800239};
240
Alan Cox806c35f2006-01-18 17:44:08 -0800241static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700242 unsigned long page)
Alan Cox806c35f2006-01-18 17:44:08 -0800243{
244 u32 remap;
Dave Jiang203333c2007-07-19 01:50:06 -0700245 struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
Alan Cox806c35f2006-01-18 17:44:08 -0800246
Dave Peterson537fba22006-03-26 01:38:40 -0800247 debugf3("%s()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -0800248
249 if (page < pvt->tolm)
250 return page;
Dave Petersone7ecd892006-03-26 01:38:52 -0800251
Alan Cox806c35f2006-01-18 17:44:08 -0800252 if ((page >= 0x100000) && (page < pvt->remapbase))
253 return page;
Dave Petersone7ecd892006-03-26 01:38:52 -0800254
Alan Cox806c35f2006-01-18 17:44:08 -0800255 remap = (page - pvt->tolm) + pvt->remapbase;
Dave Petersone7ecd892006-03-26 01:38:52 -0800256
Alan Cox806c35f2006-01-18 17:44:08 -0800257 if (remap < pvt->remaplimit)
258 return remap;
Dave Petersone7ecd892006-03-26 01:38:52 -0800259
Dave Peterson537fba22006-03-26 01:38:40 -0800260 e752x_printk(KERN_ERR, "Invalid page %lx - out of range\n", page);
Alan Cox806c35f2006-01-18 17:44:08 -0800261 return pvt->tolm - 1;
262}
263
264static void do_process_ce(struct mem_ctl_info *mci, u16 error_one,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700265 u32 sec1_add, u16 sec1_syndrome)
Alan Cox806c35f2006-01-18 17:44:08 -0800266{
267 u32 page;
268 int row;
269 int channel;
270 int i;
Dave Jiang203333c2007-07-19 01:50:06 -0700271 struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
Alan Cox806c35f2006-01-18 17:44:08 -0800272
Dave Peterson537fba22006-03-26 01:38:40 -0800273 debugf3("%s()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -0800274
275 /* convert the addr to 4k page */
276 page = sec1_add >> (PAGE_SHIFT - 4);
277
278 /* FIXME - check for -1 */
279 if (pvt->mc_symmetric) {
280 /* chip select are bits 14 & 13 */
281 row = ((page >> 1) & 3);
Dave Peterson537fba22006-03-26 01:38:40 -0800282 e752x_printk(KERN_WARNING,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700283 "Test row %d Table %d %d %d %d %d %d %d %d\n", row,
284 pvt->map[0], pvt->map[1], pvt->map[2], pvt->map[3],
285 pvt->map[4], pvt->map[5], pvt->map[6],
286 pvt->map[7]);
Alan Cox806c35f2006-01-18 17:44:08 -0800287
288 /* test for channel remapping */
289 for (i = 0; i < 8; i++) {
290 if (pvt->map[i] == row)
291 break;
292 }
Dave Petersone7ecd892006-03-26 01:38:52 -0800293
Dave Peterson537fba22006-03-26 01:38:40 -0800294 e752x_printk(KERN_WARNING, "Test computed row %d\n", i);
Dave Petersone7ecd892006-03-26 01:38:52 -0800295
Alan Cox806c35f2006-01-18 17:44:08 -0800296 if (i < 8)
297 row = i;
298 else
Dave Peterson537fba22006-03-26 01:38:40 -0800299 e752x_mc_printk(mci, KERN_WARNING,
Dave Jiang203333c2007-07-19 01:50:06 -0700300 "row %d not found in remap table\n",
301 row);
Alan Cox806c35f2006-01-18 17:44:08 -0800302 } else
303 row = edac_mc_find_csrow_by_page(mci, page);
Dave Petersone7ecd892006-03-26 01:38:52 -0800304
Alan Cox806c35f2006-01-18 17:44:08 -0800305 /* 0 = channel A, 1 = channel B */
306 channel = !(error_one & 1);
307
Mike Chan84db0032007-02-12 00:53:06 -0800308 /* e752x mc reads 34:6 of the DRAM linear address */
309 edac_mc_handle_ce(mci, page, offset_in_page(sec1_add << 4),
Douglas Thompson052dfb42007-07-19 01:50:13 -0700310 sec1_syndrome, row, channel, "e752x CE");
Dave Petersone7ecd892006-03-26 01:38:52 -0800311}
Alan Cox806c35f2006-01-18 17:44:08 -0800312
313static inline void process_ce(struct mem_ctl_info *mci, u16 error_one,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700314 u32 sec1_add, u16 sec1_syndrome, int *error_found,
315 int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800316{
317 *error_found = 1;
318
319 if (handle_error)
320 do_process_ce(mci, error_one, sec1_add, sec1_syndrome);
321}
322
Dave Petersone7ecd892006-03-26 01:38:52 -0800323static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700324 u32 ded_add, u32 scrb_add)
Alan Cox806c35f2006-01-18 17:44:08 -0800325{
326 u32 error_2b, block_page;
327 int row;
Dave Jiang203333c2007-07-19 01:50:06 -0700328 struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
Alan Cox806c35f2006-01-18 17:44:08 -0800329
Dave Peterson537fba22006-03-26 01:38:40 -0800330 debugf3("%s()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -0800331
332 if (error_one & 0x0202) {
333 error_2b = ded_add;
Dave Petersone7ecd892006-03-26 01:38:52 -0800334
Alan Cox806c35f2006-01-18 17:44:08 -0800335 /* convert to 4k address */
336 block_page = error_2b >> (PAGE_SHIFT - 4);
Dave Petersone7ecd892006-03-26 01:38:52 -0800337
Alan Cox806c35f2006-01-18 17:44:08 -0800338 row = pvt->mc_symmetric ?
Douglas Thompson052dfb42007-07-19 01:50:13 -0700339 /* chip select are bits 14 & 13 */
340 ((block_page >> 1) & 3) :
341 edac_mc_find_csrow_by_page(mci, block_page);
Dave Petersone7ecd892006-03-26 01:38:52 -0800342
Mike Chan84db0032007-02-12 00:53:06 -0800343 /* e752x mc reads 34:6 of the DRAM linear address */
344 edac_mc_handle_ue(mci, block_page,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700345 offset_in_page(error_2b << 4),
346 row, "e752x UE from Read");
Alan Cox806c35f2006-01-18 17:44:08 -0800347 }
348 if (error_one & 0x0404) {
349 error_2b = scrb_add;
Dave Petersone7ecd892006-03-26 01:38:52 -0800350
Alan Cox806c35f2006-01-18 17:44:08 -0800351 /* convert to 4k address */
352 block_page = error_2b >> (PAGE_SHIFT - 4);
Dave Petersone7ecd892006-03-26 01:38:52 -0800353
Alan Cox806c35f2006-01-18 17:44:08 -0800354 row = pvt->mc_symmetric ?
Douglas Thompson052dfb42007-07-19 01:50:13 -0700355 /* chip select are bits 14 & 13 */
356 ((block_page >> 1) & 3) :
357 edac_mc_find_csrow_by_page(mci, block_page);
Dave Petersone7ecd892006-03-26 01:38:52 -0800358
Mike Chan84db0032007-02-12 00:53:06 -0800359 /* e752x mc reads 34:6 of the DRAM linear address */
360 edac_mc_handle_ue(mci, block_page,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700361 offset_in_page(error_2b << 4),
362 row, "e752x UE from Scruber");
Alan Cox806c35f2006-01-18 17:44:08 -0800363 }
364}
365
366static inline void process_ue(struct mem_ctl_info *mci, u16 error_one,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700367 u32 ded_add, u32 scrb_add, int *error_found,
368 int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800369{
370 *error_found = 1;
371
372 if (handle_error)
373 do_process_ue(mci, error_one, ded_add, scrb_add);
374}
375
376static inline void process_ue_no_info_wr(struct mem_ctl_info *mci,
Dave Jiang203333c2007-07-19 01:50:06 -0700377 int *error_found, int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800378{
379 *error_found = 1;
380
381 if (!handle_error)
382 return;
383
Dave Peterson537fba22006-03-26 01:38:40 -0800384 debugf3("%s()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -0800385 edac_mc_handle_ue_no_info(mci, "e752x UE log memory write");
386}
387
388static void do_process_ded_retry(struct mem_ctl_info *mci, u16 error,
Dave Jiang203333c2007-07-19 01:50:06 -0700389 u32 retry_add)
Alan Cox806c35f2006-01-18 17:44:08 -0800390{
391 u32 error_1b, page;
392 int row;
Dave Jiang203333c2007-07-19 01:50:06 -0700393 struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
Alan Cox806c35f2006-01-18 17:44:08 -0800394
395 error_1b = retry_add;
Dave Jiang203333c2007-07-19 01:50:06 -0700396 page = error_1b >> (PAGE_SHIFT - 4); /* convert the addr to 4k page */
397 row = pvt->mc_symmetric ? ((page >> 1) & 3) : /* chip select are bits 14 & 13 */
Douglas Thompson052dfb42007-07-19 01:50:13 -0700398 edac_mc_find_csrow_by_page(mci, page);
Dave Peterson537fba22006-03-26 01:38:40 -0800399 e752x_mc_printk(mci, KERN_WARNING,
Dave Jiang203333c2007-07-19 01:50:06 -0700400 "CE page 0x%lx, row %d : Memory read retry\n",
401 (long unsigned int)page, row);
Alan Cox806c35f2006-01-18 17:44:08 -0800402}
403
404static inline void process_ded_retry(struct mem_ctl_info *mci, u16 error,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700405 u32 retry_add, int *error_found,
406 int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800407{
408 *error_found = 1;
409
410 if (handle_error)
411 do_process_ded_retry(mci, error, retry_add);
412}
413
414static inline void process_threshold_ce(struct mem_ctl_info *mci, u16 error,
Dave Jiang203333c2007-07-19 01:50:06 -0700415 int *error_found, int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800416{
417 *error_found = 1;
418
419 if (handle_error)
Dave Peterson537fba22006-03-26 01:38:40 -0800420 e752x_mc_printk(mci, KERN_WARNING, "Memory threshold CE\n");
Alan Cox806c35f2006-01-18 17:44:08 -0800421}
422
Alan Coxda9bb1d2006-01-18 17:44:13 -0800423static char *global_message[11] = {
Alan Cox806c35f2006-01-18 17:44:08 -0800424 "PCI Express C1", "PCI Express C", "PCI Express B1",
425 "PCI Express B", "PCI Express A1", "PCI Express A",
Andrei Konovalov5135b792008-04-29 01:03:13 -0700426 "DMA Controler", "HUB or NS Interface", "System Bus",
Alan Cox806c35f2006-01-18 17:44:08 -0800427 "DRAM Controler", "Internal Buffer"
428};
429
Alan Coxda9bb1d2006-01-18 17:44:13 -0800430static char *fatal_message[2] = { "Non-Fatal ", "Fatal " };
Alan Cox806c35f2006-01-18 17:44:08 -0800431
432static void do_global_error(int fatal, u32 errors)
433{
434 int i;
435
436 for (i = 0; i < 11; i++) {
437 if (errors & (1 << i))
Dave Peterson537fba22006-03-26 01:38:40 -0800438 e752x_printk(KERN_WARNING, "%sError %s\n",
Douglas Thompson052dfb42007-07-19 01:50:13 -0700439 fatal_message[fatal], global_message[i]);
Alan Cox806c35f2006-01-18 17:44:08 -0800440 }
441}
442
443static inline void global_error(int fatal, u32 errors, int *error_found,
Dave Jiang203333c2007-07-19 01:50:06 -0700444 int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800445{
446 *error_found = 1;
447
448 if (handle_error)
449 do_global_error(fatal, errors);
450}
451
Alan Coxda9bb1d2006-01-18 17:44:13 -0800452static char *hub_message[7] = {
Alan Cox806c35f2006-01-18 17:44:08 -0800453 "HI Address or Command Parity", "HI Illegal Access",
454 "HI Internal Parity", "Out of Range Access",
455 "HI Data Parity", "Enhanced Config Access",
456 "Hub Interface Target Abort"
457};
458
459static void do_hub_error(int fatal, u8 errors)
460{
461 int i;
462
463 for (i = 0; i < 7; i++) {
464 if (errors & (1 << i))
Dave Peterson537fba22006-03-26 01:38:40 -0800465 e752x_printk(KERN_WARNING, "%sError %s\n",
Douglas Thompson052dfb42007-07-19 01:50:13 -0700466 fatal_message[fatal], hub_message[i]);
Alan Cox806c35f2006-01-18 17:44:08 -0800467 }
468}
469
470static inline void hub_error(int fatal, u8 errors, int *error_found,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700471 int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800472{
473 *error_found = 1;
474
475 if (handle_error)
476 do_hub_error(fatal, errors);
477}
478
Andrei Konovalov5135b792008-04-29 01:03:13 -0700479#define NSI_FATAL_MASK 0x0c080081
480#define NSI_NON_FATAL_MASK 0x23a0ba64
481#define NSI_ERR_MASK (NSI_FATAL_MASK | NSI_NON_FATAL_MASK)
482
483static char *nsi_message[30] = {
484 "NSI Link Down", /* NSI_FERR/NSI_NERR bit 0, fatal error */
485 "", /* reserved */
486 "NSI Parity Error", /* bit 2, non-fatal */
487 "", /* reserved */
488 "", /* reserved */
489 "Correctable Error Message", /* bit 5, non-fatal */
490 "Non-Fatal Error Message", /* bit 6, non-fatal */
491 "Fatal Error Message", /* bit 7, fatal */
492 "", /* reserved */
493 "Receiver Error", /* bit 9, non-fatal */
494 "", /* reserved */
495 "Bad TLP", /* bit 11, non-fatal */
496 "Bad DLLP", /* bit 12, non-fatal */
497 "REPLAY_NUM Rollover", /* bit 13, non-fatal */
498 "", /* reserved */
499 "Replay Timer Timeout", /* bit 15, non-fatal */
500 "", /* reserved */
501 "", /* reserved */
502 "", /* reserved */
503 "Data Link Protocol Error", /* bit 19, fatal */
504 "", /* reserved */
505 "Poisoned TLP", /* bit 21, non-fatal */
506 "", /* reserved */
507 "Completion Timeout", /* bit 23, non-fatal */
508 "Completer Abort", /* bit 24, non-fatal */
509 "Unexpected Completion", /* bit 25, non-fatal */
510 "Receiver Overflow", /* bit 26, fatal */
511 "Malformed TLP", /* bit 27, fatal */
512 "", /* reserved */
513 "Unsupported Request" /* bit 29, non-fatal */
514};
515
516static void do_nsi_error(int fatal, u32 errors)
517{
518 int i;
519
520 for (i = 0; i < 30; i++) {
521 if (errors & (1 << i))
522 printk(KERN_WARNING "%sError %s\n",
523 fatal_message[fatal], nsi_message[i]);
524 }
525}
526
527static inline void nsi_error(int fatal, u32 errors, int *error_found,
528 int handle_error)
529{
530 *error_found = 1;
531
532 if (handle_error)
533 do_nsi_error(fatal, errors);
534}
535
Alan Coxda9bb1d2006-01-18 17:44:13 -0800536static char *membuf_message[4] = {
Alan Cox806c35f2006-01-18 17:44:08 -0800537 "Internal PMWB to DRAM parity",
538 "Internal PMWB to System Bus Parity",
539 "Internal System Bus or IO to PMWB Parity",
540 "Internal DRAM to PMWB Parity"
541};
542
543static void do_membuf_error(u8 errors)
544{
545 int i;
546
547 for (i = 0; i < 4; i++) {
548 if (errors & (1 << i))
Dave Peterson537fba22006-03-26 01:38:40 -0800549 e752x_printk(KERN_WARNING, "Non-Fatal Error %s\n",
Douglas Thompson052dfb42007-07-19 01:50:13 -0700550 membuf_message[i]);
Alan Cox806c35f2006-01-18 17:44:08 -0800551 }
552}
553
554static inline void membuf_error(u8 errors, int *error_found, int handle_error)
555{
556 *error_found = 1;
557
558 if (handle_error)
559 do_membuf_error(errors);
560}
561
Dave Petersone0093562006-03-26 01:38:54 -0800562static char *sysbus_message[10] = {
Alan Cox806c35f2006-01-18 17:44:08 -0800563 "Addr or Request Parity",
564 "Data Strobe Glitch",
565 "Addr Strobe Glitch",
566 "Data Parity",
567 "Addr Above TOM",
568 "Non DRAM Lock Error",
569 "MCERR", "BINIT",
570 "Memory Parity",
571 "IO Subsystem Parity"
572};
573
574static void do_sysbus_error(int fatal, u32 errors)
575{
576 int i;
577
578 for (i = 0; i < 10; i++) {
579 if (errors & (1 << i))
Dave Peterson537fba22006-03-26 01:38:40 -0800580 e752x_printk(KERN_WARNING, "%sError System Bus %s\n",
Douglas Thompson052dfb42007-07-19 01:50:13 -0700581 fatal_message[fatal], sysbus_message[i]);
Alan Cox806c35f2006-01-18 17:44:08 -0800582 }
583}
584
585static inline void sysbus_error(int fatal, u32 errors, int *error_found,
Dave Jiang203333c2007-07-19 01:50:06 -0700586 int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800587{
588 *error_found = 1;
589
590 if (handle_error)
591 do_sysbus_error(fatal, errors);
592}
593
Dave Petersone7ecd892006-03-26 01:38:52 -0800594static void e752x_check_hub_interface(struct e752x_error_info *info,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700595 int *error_found, int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800596{
597 u8 stat8;
598
599 //pci_read_config_byte(dev,E752X_HI_FERR,&stat8);
Dave Petersone7ecd892006-03-26 01:38:52 -0800600
Alan Cox806c35f2006-01-18 17:44:08 -0800601 stat8 = info->hi_ferr;
Dave Petersone7ecd892006-03-26 01:38:52 -0800602
Dave Jiang203333c2007-07-19 01:50:06 -0700603 if (stat8 & 0x7f) { /* Error, so process */
Alan Cox806c35f2006-01-18 17:44:08 -0800604 stat8 &= 0x7f;
Dave Petersone7ecd892006-03-26 01:38:52 -0800605
Alan Cox806c35f2006-01-18 17:44:08 -0800606 if (stat8 & 0x2b)
607 hub_error(1, stat8 & 0x2b, error_found, handle_error);
Dave Petersone7ecd892006-03-26 01:38:52 -0800608
Dave Jiang203333c2007-07-19 01:50:06 -0700609 if (stat8 & 0x54)
610 hub_error(0, stat8 & 0x54, error_found, handle_error);
611 }
612 //pci_read_config_byte(dev,E752X_HI_NERR,&stat8);
613
614 stat8 = info->hi_nerr;
615
616 if (stat8 & 0x7f) { /* Error, so process */
617 stat8 &= 0x7f;
618
619 if (stat8 & 0x2b)
620 hub_error(1, stat8 & 0x2b, error_found, handle_error);
621
622 if (stat8 & 0x54)
Alan Cox806c35f2006-01-18 17:44:08 -0800623 hub_error(0, stat8 & 0x54, error_found, handle_error);
624 }
625}
626
Andrei Konovalov5135b792008-04-29 01:03:13 -0700627static void e752x_check_ns_interface(struct e752x_error_info *info,
628 int *error_found, int handle_error)
629{
630 u32 stat32;
631
632 stat32 = info->nsi_ferr;
633 if (stat32 & NSI_ERR_MASK) { /* Error, so process */
634 if (stat32 & NSI_FATAL_MASK) /* check for fatal errors */
635 nsi_error(1, stat32 & NSI_FATAL_MASK, error_found,
636 handle_error);
637 if (stat32 & NSI_NON_FATAL_MASK) /* check for non-fatal ones */
638 nsi_error(0, stat32 & NSI_NON_FATAL_MASK, error_found,
639 handle_error);
640 }
641 stat32 = info->nsi_nerr;
642 if (stat32 & NSI_ERR_MASK) {
643 if (stat32 & NSI_FATAL_MASK)
644 nsi_error(1, stat32 & NSI_FATAL_MASK, error_found,
645 handle_error);
646 if (stat32 & NSI_NON_FATAL_MASK)
647 nsi_error(0, stat32 & NSI_NON_FATAL_MASK, error_found,
648 handle_error);
649 }
650}
651
Dave Petersone7ecd892006-03-26 01:38:52 -0800652static void e752x_check_sysbus(struct e752x_error_info *info,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700653 int *error_found, int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800654{
655 u32 stat32, error32;
656
657 //pci_read_config_dword(dev,E752X_SYSBUS_FERR,&stat32);
658 stat32 = info->sysbus_ferr + (info->sysbus_nerr << 16);
659
660 if (stat32 == 0)
Dave Jiang203333c2007-07-19 01:50:06 -0700661 return; /* no errors */
Alan Cox806c35f2006-01-18 17:44:08 -0800662
663 error32 = (stat32 >> 16) & 0x3ff;
664 stat32 = stat32 & 0x3ff;
Dave Petersone7ecd892006-03-26 01:38:52 -0800665
Dave Jiang203333c2007-07-19 01:50:06 -0700666 if (stat32 & 0x087)
Brian Pomerantzdfb2a762007-02-12 00:53:03 -0800667 sysbus_error(1, stat32 & 0x087, error_found, handle_error);
Dave Petersone7ecd892006-03-26 01:38:52 -0800668
Dave Jiang203333c2007-07-19 01:50:06 -0700669 if (stat32 & 0x378)
Brian Pomerantzdfb2a762007-02-12 00:53:03 -0800670 sysbus_error(0, stat32 & 0x378, error_found, handle_error);
Dave Petersone7ecd892006-03-26 01:38:52 -0800671
Dave Jiang203333c2007-07-19 01:50:06 -0700672 if (error32 & 0x087)
Brian Pomerantzdfb2a762007-02-12 00:53:03 -0800673 sysbus_error(1, error32 & 0x087, error_found, handle_error);
Dave Petersone7ecd892006-03-26 01:38:52 -0800674
Dave Jiang203333c2007-07-19 01:50:06 -0700675 if (error32 & 0x378)
Brian Pomerantzdfb2a762007-02-12 00:53:03 -0800676 sysbus_error(0, error32 & 0x378, error_found, handle_error);
Alan Cox806c35f2006-01-18 17:44:08 -0800677}
678
Dave Jiang203333c2007-07-19 01:50:06 -0700679static void e752x_check_membuf(struct e752x_error_info *info,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700680 int *error_found, int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800681{
682 u8 stat8;
683
684 stat8 = info->buf_ferr;
Dave Petersone7ecd892006-03-26 01:38:52 -0800685
Dave Jiang203333c2007-07-19 01:50:06 -0700686 if (stat8 & 0x0f) { /* Error, so process */
Alan Cox806c35f2006-01-18 17:44:08 -0800687 stat8 &= 0x0f;
688 membuf_error(stat8, error_found, handle_error);
689 }
Dave Petersone7ecd892006-03-26 01:38:52 -0800690
Alan Cox806c35f2006-01-18 17:44:08 -0800691 stat8 = info->buf_nerr;
Dave Petersone7ecd892006-03-26 01:38:52 -0800692
Dave Jiang203333c2007-07-19 01:50:06 -0700693 if (stat8 & 0x0f) { /* Error, so process */
Alan Cox806c35f2006-01-18 17:44:08 -0800694 stat8 &= 0x0f;
695 membuf_error(stat8, error_found, handle_error);
696 }
697}
698
Dave Jiang203333c2007-07-19 01:50:06 -0700699static void e752x_check_dram(struct mem_ctl_info *mci,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700700 struct e752x_error_info *info, int *error_found,
701 int handle_error)
Alan Cox806c35f2006-01-18 17:44:08 -0800702{
703 u16 error_one, error_next;
704
705 error_one = info->dram_ferr;
706 error_next = info->dram_nerr;
707
708 /* decode and report errors */
Dave Jiang203333c2007-07-19 01:50:06 -0700709 if (error_one & 0x0101) /* check first error correctable */
Alan Cox806c35f2006-01-18 17:44:08 -0800710 process_ce(mci, error_one, info->dram_sec1_add,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700711 info->dram_sec1_syndrome, error_found, handle_error);
Alan Cox806c35f2006-01-18 17:44:08 -0800712
Dave Jiang203333c2007-07-19 01:50:06 -0700713 if (error_next & 0x0101) /* check next error correctable */
Alan Cox806c35f2006-01-18 17:44:08 -0800714 process_ce(mci, error_next, info->dram_sec2_add,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700715 info->dram_sec2_syndrome, error_found, handle_error);
Alan Cox806c35f2006-01-18 17:44:08 -0800716
Dave Jiang203333c2007-07-19 01:50:06 -0700717 if (error_one & 0x4040)
Alan Cox806c35f2006-01-18 17:44:08 -0800718 process_ue_no_info_wr(mci, error_found, handle_error);
719
Dave Jiang203333c2007-07-19 01:50:06 -0700720 if (error_next & 0x4040)
Alan Cox806c35f2006-01-18 17:44:08 -0800721 process_ue_no_info_wr(mci, error_found, handle_error);
722
Dave Jiang203333c2007-07-19 01:50:06 -0700723 if (error_one & 0x2020)
Alan Cox806c35f2006-01-18 17:44:08 -0800724 process_ded_retry(mci, error_one, info->dram_retr_add,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700725 error_found, handle_error);
Alan Cox806c35f2006-01-18 17:44:08 -0800726
Dave Jiang203333c2007-07-19 01:50:06 -0700727 if (error_next & 0x2020)
Alan Cox806c35f2006-01-18 17:44:08 -0800728 process_ded_retry(mci, error_next, info->dram_retr_add,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700729 error_found, handle_error);
Alan Cox806c35f2006-01-18 17:44:08 -0800730
Dave Jiang203333c2007-07-19 01:50:06 -0700731 if (error_one & 0x0808)
732 process_threshold_ce(mci, error_one, error_found, handle_error);
Alan Cox806c35f2006-01-18 17:44:08 -0800733
Dave Jiang203333c2007-07-19 01:50:06 -0700734 if (error_next & 0x0808)
Alan Cox806c35f2006-01-18 17:44:08 -0800735 process_threshold_ce(mci, error_next, error_found,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700736 handle_error);
Alan Cox806c35f2006-01-18 17:44:08 -0800737
Dave Jiang203333c2007-07-19 01:50:06 -0700738 if (error_one & 0x0606)
Alan Cox806c35f2006-01-18 17:44:08 -0800739 process_ue(mci, error_one, info->dram_ded_add,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700740 info->dram_scrb_add, error_found, handle_error);
Alan Cox806c35f2006-01-18 17:44:08 -0800741
Dave Jiang203333c2007-07-19 01:50:06 -0700742 if (error_next & 0x0606)
Alan Cox806c35f2006-01-18 17:44:08 -0800743 process_ue(mci, error_next, info->dram_ded_add,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700744 info->dram_scrb_add, error_found, handle_error);
Alan Cox806c35f2006-01-18 17:44:08 -0800745}
746
Dave Jiang203333c2007-07-19 01:50:06 -0700747static void e752x_get_error_info(struct mem_ctl_info *mci,
748 struct e752x_error_info *info)
Alan Cox806c35f2006-01-18 17:44:08 -0800749{
750 struct pci_dev *dev;
751 struct e752x_pvt *pvt;
752
753 memset(info, 0, sizeof(*info));
Dave Jiang203333c2007-07-19 01:50:06 -0700754 pvt = (struct e752x_pvt *)mci->pvt_info;
Alan Cox806c35f2006-01-18 17:44:08 -0800755 dev = pvt->dev_d0f1;
Alan Cox806c35f2006-01-18 17:44:08 -0800756 pci_read_config_dword(dev, E752X_FERR_GLOBAL, &info->ferr_global);
757
758 if (info->ferr_global) {
Andrei Konovalov5135b792008-04-29 01:03:13 -0700759 if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) {
760 pci_read_config_dword(dev, I3100_NSI_FERR,
761 &info->nsi_ferr);
762 info->hi_ferr = 0;
763 } else {
764 pci_read_config_byte(dev, E752X_HI_FERR,
765 &info->hi_ferr);
766 info->nsi_ferr = 0;
767 }
Alan Cox806c35f2006-01-18 17:44:08 -0800768 pci_read_config_word(dev, E752X_SYSBUS_FERR,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700769 &info->sysbus_ferr);
Alan Cox806c35f2006-01-18 17:44:08 -0800770 pci_read_config_byte(dev, E752X_BUF_FERR, &info->buf_ferr);
Dave Jiang203333c2007-07-19 01:50:06 -0700771 pci_read_config_word(dev, E752X_DRAM_FERR, &info->dram_ferr);
Alan Cox806c35f2006-01-18 17:44:08 -0800772 pci_read_config_dword(dev, E752X_DRAM_SEC1_ADD,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700773 &info->dram_sec1_add);
Alan Cox806c35f2006-01-18 17:44:08 -0800774 pci_read_config_word(dev, E752X_DRAM_SEC1_SYNDROME,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700775 &info->dram_sec1_syndrome);
Alan Cox806c35f2006-01-18 17:44:08 -0800776 pci_read_config_dword(dev, E752X_DRAM_DED_ADD,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700777 &info->dram_ded_add);
Alan Cox806c35f2006-01-18 17:44:08 -0800778 pci_read_config_dword(dev, E752X_DRAM_SCRB_ADD,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700779 &info->dram_scrb_add);
Alan Cox806c35f2006-01-18 17:44:08 -0800780 pci_read_config_dword(dev, E752X_DRAM_RETR_ADD,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700781 &info->dram_retr_add);
Alan Cox806c35f2006-01-18 17:44:08 -0800782
Andrei Konovalov5135b792008-04-29 01:03:13 -0700783 /* ignore the reserved bits just in case */
Alan Cox806c35f2006-01-18 17:44:08 -0800784 if (info->hi_ferr & 0x7f)
785 pci_write_config_byte(dev, E752X_HI_FERR,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700786 info->hi_ferr);
Alan Cox806c35f2006-01-18 17:44:08 -0800787
Andrei Konovalov5135b792008-04-29 01:03:13 -0700788 if (info->nsi_ferr & NSI_ERR_MASK)
789 pci_write_config_dword(dev, I3100_NSI_FERR,
790 info->nsi_ferr);
791
Alan Cox806c35f2006-01-18 17:44:08 -0800792 if (info->sysbus_ferr)
793 pci_write_config_word(dev, E752X_SYSBUS_FERR,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700794 info->sysbus_ferr);
Alan Cox806c35f2006-01-18 17:44:08 -0800795
796 if (info->buf_ferr & 0x0f)
797 pci_write_config_byte(dev, E752X_BUF_FERR,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700798 info->buf_ferr);
Alan Cox806c35f2006-01-18 17:44:08 -0800799
800 if (info->dram_ferr)
801 pci_write_bits16(pvt->bridge_ck, E752X_DRAM_FERR,
Dave Jiang203333c2007-07-19 01:50:06 -0700802 info->dram_ferr, info->dram_ferr);
Alan Cox806c35f2006-01-18 17:44:08 -0800803
804 pci_write_config_dword(dev, E752X_FERR_GLOBAL,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700805 info->ferr_global);
Alan Cox806c35f2006-01-18 17:44:08 -0800806 }
807
808 pci_read_config_dword(dev, E752X_NERR_GLOBAL, &info->nerr_global);
809
810 if (info->nerr_global) {
Andrei Konovalov5135b792008-04-29 01:03:13 -0700811 if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) {
812 pci_read_config_dword(dev, I3100_NSI_NERR,
813 &info->nsi_nerr);
814 info->hi_nerr = 0;
815 } else {
816 pci_read_config_byte(dev, E752X_HI_NERR,
817 &info->hi_nerr);
818 info->nsi_nerr = 0;
819 }
Alan Cox806c35f2006-01-18 17:44:08 -0800820 pci_read_config_word(dev, E752X_SYSBUS_NERR,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700821 &info->sysbus_nerr);
Alan Cox806c35f2006-01-18 17:44:08 -0800822 pci_read_config_byte(dev, E752X_BUF_NERR, &info->buf_nerr);
Dave Jiang203333c2007-07-19 01:50:06 -0700823 pci_read_config_word(dev, E752X_DRAM_NERR, &info->dram_nerr);
Alan Cox806c35f2006-01-18 17:44:08 -0800824 pci_read_config_dword(dev, E752X_DRAM_SEC2_ADD,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700825 &info->dram_sec2_add);
Alan Cox806c35f2006-01-18 17:44:08 -0800826 pci_read_config_word(dev, E752X_DRAM_SEC2_SYNDROME,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700827 &info->dram_sec2_syndrome);
Alan Cox806c35f2006-01-18 17:44:08 -0800828
829 if (info->hi_nerr & 0x7f)
830 pci_write_config_byte(dev, E752X_HI_NERR,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700831 info->hi_nerr);
Alan Cox806c35f2006-01-18 17:44:08 -0800832
Andrei Konovalov5135b792008-04-29 01:03:13 -0700833 if (info->nsi_nerr & NSI_ERR_MASK)
834 pci_write_config_dword(dev, I3100_NSI_NERR,
835 info->nsi_nerr);
836
Alan Cox806c35f2006-01-18 17:44:08 -0800837 if (info->sysbus_nerr)
838 pci_write_config_word(dev, E752X_SYSBUS_NERR,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700839 info->sysbus_nerr);
Alan Cox806c35f2006-01-18 17:44:08 -0800840
841 if (info->buf_nerr & 0x0f)
842 pci_write_config_byte(dev, E752X_BUF_NERR,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700843 info->buf_nerr);
Alan Cox806c35f2006-01-18 17:44:08 -0800844
845 if (info->dram_nerr)
846 pci_write_bits16(pvt->bridge_ck, E752X_DRAM_NERR,
Dave Jiang203333c2007-07-19 01:50:06 -0700847 info->dram_nerr, info->dram_nerr);
Alan Cox806c35f2006-01-18 17:44:08 -0800848
849 pci_write_config_dword(dev, E752X_NERR_GLOBAL,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700850 info->nerr_global);
Alan Cox806c35f2006-01-18 17:44:08 -0800851 }
852}
853
Dave Jiang203333c2007-07-19 01:50:06 -0700854static int e752x_process_error_info(struct mem_ctl_info *mci,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700855 struct e752x_error_info *info,
856 int handle_errors)
Alan Cox806c35f2006-01-18 17:44:08 -0800857{
858 u32 error32, stat32;
859 int error_found;
860
861 error_found = 0;
862 error32 = (info->ferr_global >> 18) & 0x3ff;
863 stat32 = (info->ferr_global >> 4) & 0x7ff;
864
865 if (error32)
866 global_error(1, error32, &error_found, handle_errors);
867
868 if (stat32)
869 global_error(0, stat32, &error_found, handle_errors);
870
871 error32 = (info->nerr_global >> 18) & 0x3ff;
872 stat32 = (info->nerr_global >> 4) & 0x7ff;
873
874 if (error32)
875 global_error(1, error32, &error_found, handle_errors);
876
877 if (stat32)
878 global_error(0, stat32, &error_found, handle_errors);
879
880 e752x_check_hub_interface(info, &error_found, handle_errors);
Andrei Konovalov5135b792008-04-29 01:03:13 -0700881 e752x_check_ns_interface(info, &error_found, handle_errors);
Alan Cox806c35f2006-01-18 17:44:08 -0800882 e752x_check_sysbus(info, &error_found, handle_errors);
883 e752x_check_membuf(info, &error_found, handle_errors);
884 e752x_check_dram(mci, info, &error_found, handle_errors);
885 return error_found;
886}
887
888static void e752x_check(struct mem_ctl_info *mci)
889{
890 struct e752x_error_info info;
Dave Petersone7ecd892006-03-26 01:38:52 -0800891
Dave Peterson537fba22006-03-26 01:38:40 -0800892 debugf3("%s()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -0800893 e752x_get_error_info(mci, &info);
894 e752x_process_error_info(mci, &info, 1);
895}
896
Doug Thompson13189522006-06-30 01:56:08 -0700897/* Return 1 if dual channel mode is active. Else return 0. */
898static inline int dual_channel_active(u16 ddrcsr)
Alan Cox806c35f2006-01-18 17:44:08 -0800899{
Doug Thompson13189522006-06-30 01:56:08 -0700900 return (((ddrcsr >> 12) & 3) == 3);
901}
902
Mark Grondona7297c262007-07-19 01:50:23 -0700903/* Remap csrow index numbers if map_type is "reverse"
904 */
905static inline int remap_csrow_index(struct mem_ctl_info *mci, int index)
906{
907 struct e752x_pvt *pvt = mci->pvt_info;
908
909 if (!pvt->map_type)
910 return (7 - index);
911
912 return (index);
913}
914
Doug Thompson13189522006-06-30 01:56:08 -0700915static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700916 u16 ddrcsr)
Doug Thompson13189522006-06-30 01:56:08 -0700917{
918 struct csrow_info *csrow;
Alan Cox806c35f2006-01-18 17:44:08 -0800919 unsigned long last_cumul_size;
Doug Thompson13189522006-06-30 01:56:08 -0700920 int index, mem_dev, drc_chan;
Dave Jiang203333c2007-07-19 01:50:06 -0700921 int drc_drbg; /* DRB granularity 0=64mb, 1=128mb */
922 int drc_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */
Doug Thompson13189522006-06-30 01:56:08 -0700923 u8 value;
924 u32 dra, drc, cumul_size;
Alan Cox806c35f2006-01-18 17:44:08 -0800925
Brian Pomerantz9962fd02007-02-12 00:53:05 -0800926 dra = 0;
Dave Jiang203333c2007-07-19 01:50:06 -0700927 for (index = 0; index < 4; index++) {
Brian Pomerantz9962fd02007-02-12 00:53:05 -0800928 u8 dra_reg;
Dave Jiang203333c2007-07-19 01:50:06 -0700929 pci_read_config_byte(pdev, E752X_DRA + index, &dra_reg);
Brian Pomerantz9962fd02007-02-12 00:53:05 -0800930 dra |= dra_reg << (index * 8);
931 }
Alan Cox806c35f2006-01-18 17:44:08 -0800932 pci_read_config_dword(pdev, E752X_DRC, &drc);
Doug Thompson13189522006-06-30 01:56:08 -0700933 drc_chan = dual_channel_active(ddrcsr);
Dave Jiang203333c2007-07-19 01:50:06 -0700934 drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */
Alan Cox806c35f2006-01-18 17:44:08 -0800935 drc_ddim = (drc >> 20) & 0x3;
936
Doug Thompson13189522006-06-30 01:56:08 -0700937 /* The dram row boundary (DRB) reg values are boundary address for
Alan Cox806c35f2006-01-18 17:44:08 -0800938 * each DRAM row with a granularity of 64 or 128MB (single/dual
939 * channel operation). DRB regs are cumulative; therefore DRB7 will
940 * contain the total memory contained in all eight rows.
941 */
942 for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) {
Alan Cox806c35f2006-01-18 17:44:08 -0800943 /* mem_dev 0=x8, 1=x4 */
Doug Thompson13189522006-06-30 01:56:08 -0700944 mem_dev = (dra >> (index * 4 + 2)) & 0x3;
Mark Grondona7297c262007-07-19 01:50:23 -0700945 csrow = &mci->csrows[remap_csrow_index(mci, index)];
Alan Cox806c35f2006-01-18 17:44:08 -0800946
947 mem_dev = (mem_dev == 2);
Doug Thompson37f04582006-06-30 01:56:07 -0700948 pci_read_config_byte(pdev, E752X_DRB + index, &value);
Alan Cox806c35f2006-01-18 17:44:08 -0800949 /* convert a 128 or 64 MiB DRB to a page size. */
950 cumul_size = value << (25 + drc_drbg - PAGE_SHIFT);
Dave Peterson537fba22006-03-26 01:38:40 -0800951 debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
952 cumul_size);
Alan Cox806c35f2006-01-18 17:44:08 -0800953 if (cumul_size == last_cumul_size)
Doug Thompson13189522006-06-30 01:56:08 -0700954 continue; /* not populated */
Alan Cox806c35f2006-01-18 17:44:08 -0800955
956 csrow->first_page = last_cumul_size;
957 csrow->last_page = cumul_size - 1;
958 csrow->nr_pages = cumul_size - last_cumul_size;
959 last_cumul_size = cumul_size;
Doug Thompson13189522006-06-30 01:56:08 -0700960 csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */
961 csrow->mtype = MEM_RDDR; /* only one type supported */
Alan Cox806c35f2006-01-18 17:44:08 -0800962 csrow->dtype = mem_dev ? DEV_X4 : DEV_X8;
963
964 /*
965 * if single channel or x8 devices then SECDED
966 * if dual channel and x4 then S4ECD4ED
967 */
968 if (drc_ddim) {
969 if (drc_chan && mem_dev) {
970 csrow->edac_mode = EDAC_S4ECD4ED;
971 mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
972 } else {
973 csrow->edac_mode = EDAC_SECDED;
974 mci->edac_cap |= EDAC_FLAG_SECDED;
975 }
976 } else
977 csrow->edac_mode = EDAC_NONE;
978 }
Doug Thompson13189522006-06-30 01:56:08 -0700979}
Alan Cox806c35f2006-01-18 17:44:08 -0800980
Doug Thompson13189522006-06-30 01:56:08 -0700981static void e752x_init_mem_map_table(struct pci_dev *pdev,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700982 struct e752x_pvt *pvt)
Doug Thompson13189522006-06-30 01:56:08 -0700983{
984 int index;
Mark Grondona7297c262007-07-19 01:50:23 -0700985 u8 value, last, row;
Alan Cox806c35f2006-01-18 17:44:08 -0800986
Doug Thompson13189522006-06-30 01:56:08 -0700987 last = 0;
988 row = 0;
Dave Petersone7ecd892006-03-26 01:38:52 -0800989
Doug Thompson13189522006-06-30 01:56:08 -0700990 for (index = 0; index < 8; index += 2) {
991 pci_read_config_byte(pdev, E752X_DRB + index, &value);
992 /* test if there is a dimm in this slot */
993 if (value == last) {
994 /* no dimm in the slot, so flag it as empty */
995 pvt->map[index] = 0xff;
996 pvt->map[index + 1] = 0xff;
Dave Jiang203333c2007-07-19 01:50:06 -0700997 } else { /* there is a dimm in the slot */
Doug Thompson13189522006-06-30 01:56:08 -0700998 pvt->map[index] = row;
999 row++;
1000 last = value;
1001 /* test the next value to see if the dimm is double
1002 * sided
1003 */
1004 pci_read_config_byte(pdev, E752X_DRB + index + 1,
Douglas Thompson052dfb42007-07-19 01:50:13 -07001005 &value);
1006
1007 /* the dimm is single sided, so flag as empty */
1008 /* this is a double sided dimm to save the next row #*/
1009 pvt->map[index + 1] = (value == last) ? 0xff : row;
Doug Thompson13189522006-06-30 01:56:08 -07001010 row++;
1011 last = value;
Alan Cox806c35f2006-01-18 17:44:08 -08001012 }
1013 }
Doug Thompson13189522006-06-30 01:56:08 -07001014}
1015
1016/* Return 0 on success or 1 on failure. */
1017static int e752x_get_devs(struct pci_dev *pdev, int dev_idx,
Douglas Thompson052dfb42007-07-19 01:50:13 -07001018 struct e752x_pvt *pvt)
Doug Thompson13189522006-06-30 01:56:08 -07001019{
1020 struct pci_dev *dev;
1021
1022 pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
Dave Jiang203333c2007-07-19 01:50:06 -07001023 pvt->dev_info->err_dev, pvt->bridge_ck);
Doug Thompson13189522006-06-30 01:56:08 -07001024
1025 if (pvt->bridge_ck == NULL)
1026 pvt->bridge_ck = pci_scan_single_device(pdev->bus,
1027 PCI_DEVFN(0, 1));
1028
1029 if (pvt->bridge_ck == NULL) {
1030 e752x_printk(KERN_ERR, "error reporting device not found:"
Douglas Thompson052dfb42007-07-19 01:50:13 -07001031 "vendor %x device 0x%x (broken BIOS?)\n",
1032 PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev);
Doug Thompson13189522006-06-30 01:56:08 -07001033 return 1;
1034 }
1035
1036 dev = pci_get_device(PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].ctl_dev,
Douglas Thompson052dfb42007-07-19 01:50:13 -07001037 NULL);
Doug Thompson13189522006-06-30 01:56:08 -07001038
1039 if (dev == NULL)
1040 goto fail;
1041
1042 pvt->dev_d0f0 = dev;
1043 pvt->dev_d0f1 = pci_dev_get(pvt->bridge_ck);
1044
1045 return 0;
1046
Douglas Thompson052dfb42007-07-19 01:50:13 -07001047fail:
Doug Thompson13189522006-06-30 01:56:08 -07001048 pci_dev_put(pvt->bridge_ck);
1049 return 1;
1050}
1051
1052static void e752x_init_error_reporting_regs(struct e752x_pvt *pvt)
1053{
1054 struct pci_dev *dev;
1055
1056 dev = pvt->dev_d0f1;
1057 /* Turn off error disable & SMI in case the BIOS turned it on */
Andrei Konovalov5135b792008-04-29 01:03:13 -07001058 if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) {
1059 pci_write_config_dword(dev, I3100_NSI_EMASK, 0);
1060 pci_write_config_dword(dev, I3100_NSI_SMICMD, 0);
1061 } else {
1062 pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00);
1063 pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00);
1064 }
Doug Thompson13189522006-06-30 01:56:08 -07001065 pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x00);
1066 pci_write_config_word(dev, E752X_SYSBUS_SMICMD, 0x00);
1067 pci_write_config_byte(dev, E752X_BUF_ERRMASK, 0x00);
1068 pci_write_config_byte(dev, E752X_BUF_SMICMD, 0x00);
1069 pci_write_config_byte(dev, E752X_DRAM_ERRMASK, 0x00);
1070 pci_write_config_byte(dev, E752X_DRAM_SMICMD, 0x00);
1071}
1072
1073static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
1074{
1075 u16 pci_data;
1076 u8 stat8;
1077 struct mem_ctl_info *mci;
1078 struct e752x_pvt *pvt;
1079 u16 ddrcsr;
Dave Jiang203333c2007-07-19 01:50:06 -07001080 int drc_chan; /* Number of channels 0=1chan,1=2chan */
Doug Thompson13189522006-06-30 01:56:08 -07001081 struct e752x_error_info discard;
1082
1083 debugf0("%s(): mci\n", __func__);
1084 debugf0("Starting Probe1\n");
1085
Dave Jiangc0d12172007-07-19 01:49:46 -07001086 /* make sure error reporting method is sane */
Dave Jiang203333c2007-07-19 01:50:06 -07001087 switch (edac_op_state) {
1088 case EDAC_OPSTATE_POLL:
1089 case EDAC_OPSTATE_NMI:
1090 break;
1091 default:
1092 edac_op_state = EDAC_OPSTATE_POLL;
1093 break;
Dave Jiangc0d12172007-07-19 01:49:46 -07001094 }
1095
Doug Thompson13189522006-06-30 01:56:08 -07001096 /* check to see if device 0 function 1 is enabled; if it isn't, we
1097 * assume the BIOS has reserved it for a reason and is expecting
1098 * exclusive access, we take care not to violate that assumption and
1099 * fail the probe. */
1100 pci_read_config_byte(pdev, E752X_DEVPRES1, &stat8);
1101 if (!force_function_unhide && !(stat8 & (1 << 5))) {
1102 printk(KERN_INFO "Contact your BIOS vendor to see if the "
Douglas Thompson052dfb42007-07-19 01:50:13 -07001103 "E752x error registers can be safely un-hidden\n");
Aristeu Rozanskif9b5a5d2007-09-11 15:23:32 -07001104 return -ENODEV;
Doug Thompson13189522006-06-30 01:56:08 -07001105 }
1106 stat8 |= (1 << 5);
1107 pci_write_config_byte(pdev, E752X_DEVPRES1, stat8);
1108
1109 pci_read_config_word(pdev, E752X_DDRCSR, &ddrcsr);
1110 /* FIXME: should check >>12 or 0xf, true for all? */
1111 /* Dual channel = 1, Single channel = 0 */
1112 drc_chan = dual_channel_active(ddrcsr);
1113
Doug Thompsonb8f6f972007-07-19 01:50:26 -07001114 mci = edac_mc_alloc(sizeof(*pvt), E752X_NR_CSROWS, drc_chan + 1, 0);
Doug Thompson13189522006-06-30 01:56:08 -07001115
1116 if (mci == NULL) {
1117 return -ENOMEM;
1118 }
1119
1120 debugf3("%s(): init mci\n", __func__);
1121 mci->mtype_cap = MEM_FLAG_RDDR;
Andrei Konovalov5135b792008-04-29 01:03:13 -07001122 /* 3100 IMCH supports SECDEC only */
1123 mci->edac_ctl_cap = (dev_idx == I3100) ? EDAC_FLAG_SECDED :
1124 (EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_S4ECD4ED);
Doug Thompson13189522006-06-30 01:56:08 -07001125 /* FIXME - what if different memory types are in different csrows? */
1126 mci->mod_name = EDAC_MOD_STR;
1127 mci->mod_ver = E752X_REVISION;
1128 mci->dev = &pdev->dev;
1129
1130 debugf3("%s(): init pvt\n", __func__);
Dave Jiang203333c2007-07-19 01:50:06 -07001131 pvt = (struct e752x_pvt *)mci->pvt_info;
Doug Thompson13189522006-06-30 01:56:08 -07001132 pvt->dev_info = &e752x_devs[dev_idx];
1133 pvt->mc_symmetric = ((ddrcsr & 0x10) != 0);
1134
1135 if (e752x_get_devs(pdev, dev_idx, pvt)) {
1136 edac_mc_free(mci);
1137 return -ENODEV;
1138 }
1139
1140 debugf3("%s(): more mci init\n", __func__);
1141 mci->ctl_name = pvt->dev_info->ctl_name;
Dave Jiangc4192702007-07-19 01:49:47 -07001142 mci->dev_name = pci_name(pdev);
Doug Thompson13189522006-06-30 01:56:08 -07001143 mci->edac_check = e752x_check;
1144 mci->ctl_page_to_phys = ctl_page_to_phys;
1145
Mark Grondona7297c262007-07-19 01:50:23 -07001146 /* set the map type. 1 = normal, 0 = reversed
1147 * Must be set before e752x_init_csrows in case csrow mapping
1148 * is reversed.
1149 */
Doug Thompson13189522006-06-30 01:56:08 -07001150 pci_read_config_byte(pdev, E752X_DRM, &stat8);
1151 pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f));
Alan Cox806c35f2006-01-18 17:44:08 -08001152
Mark Grondona7297c262007-07-19 01:50:23 -07001153 e752x_init_csrows(mci, pdev, ddrcsr);
1154 e752x_init_mem_map_table(pdev, pvt);
1155
Andrei Konovalov5135b792008-04-29 01:03:13 -07001156 if (dev_idx == I3100)
1157 mci->edac_cap = EDAC_FLAG_SECDED; /* the only mode supported */
1158 else
1159 mci->edac_cap |= EDAC_FLAG_NONE;
Dave Peterson537fba22006-03-26 01:38:40 -08001160 debugf3("%s(): tolm, remapbase, remaplimit\n", __func__);
Dave Petersone7ecd892006-03-26 01:38:52 -08001161
Alan Cox806c35f2006-01-18 17:44:08 -08001162 /* load the top of low memory, remap base, and remap limit vars */
Doug Thompson37f04582006-06-30 01:56:07 -07001163 pci_read_config_word(pdev, E752X_TOLM, &pci_data);
Alan Cox806c35f2006-01-18 17:44:08 -08001164 pvt->tolm = ((u32) pci_data) << 4;
Doug Thompson37f04582006-06-30 01:56:07 -07001165 pci_read_config_word(pdev, E752X_REMAPBASE, &pci_data);
Alan Cox806c35f2006-01-18 17:44:08 -08001166 pvt->remapbase = ((u32) pci_data) << 14;
Doug Thompson37f04582006-06-30 01:56:07 -07001167 pci_read_config_word(pdev, E752X_REMAPLIMIT, &pci_data);
Alan Cox806c35f2006-01-18 17:44:08 -08001168 pvt->remaplimit = ((u32) pci_data) << 14;
Dave Peterson537fba22006-03-26 01:38:40 -08001169 e752x_printk(KERN_INFO,
Douglas Thompson052dfb42007-07-19 01:50:13 -07001170 "tolm = %x, remapbase = %x, remaplimit = %x\n",
1171 pvt->tolm, pvt->remapbase, pvt->remaplimit);
Alan Cox806c35f2006-01-18 17:44:08 -08001172
Doug Thompson2d7bbb92006-06-30 01:56:08 -07001173 /* Here we assume that we will never see multiple instances of this
1174 * type of memory controller. The ID is therefore hardcoded to 0.
1175 */
Doug Thompsonb8f6f972007-07-19 01:50:26 -07001176 if (edac_mc_add_mc(mci)) {
Dave Peterson537fba22006-03-26 01:38:40 -08001177 debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -08001178 goto fail;
1179 }
1180
Doug Thompson13189522006-06-30 01:56:08 -07001181 e752x_init_error_reporting_regs(pvt);
Dave Jiang203333c2007-07-19 01:50:06 -07001182 e752x_get_error_info(mci, &discard); /* clear other MCH errors */
Alan Cox806c35f2006-01-18 17:44:08 -08001183
Dave Jiang91b99042007-07-19 01:49:52 -07001184 /* allocating generic PCI control info */
1185 e752x_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
1186 if (!e752x_pci) {
1187 printk(KERN_WARNING
Douglas Thompson052dfb42007-07-19 01:50:13 -07001188 "%s(): Unable to create PCI control\n", __func__);
Dave Jiang91b99042007-07-19 01:49:52 -07001189 printk(KERN_WARNING
Douglas Thompson052dfb42007-07-19 01:50:13 -07001190 "%s(): PCI error report via EDAC not setup\n",
1191 __func__);
Dave Jiang91b99042007-07-19 01:49:52 -07001192 }
1193
Alan Cox806c35f2006-01-18 17:44:08 -08001194 /* get this far and it's successful */
Dave Peterson537fba22006-03-26 01:38:40 -08001195 debugf3("%s(): success\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -08001196 return 0;
1197
Douglas Thompson052dfb42007-07-19 01:50:13 -07001198fail:
Doug Thompson13189522006-06-30 01:56:08 -07001199 pci_dev_put(pvt->dev_d0f0);
1200 pci_dev_put(pvt->dev_d0f1);
1201 pci_dev_put(pvt->bridge_ck);
1202 edac_mc_free(mci);
Dave Petersone7ecd892006-03-26 01:38:52 -08001203
Doug Thompson13189522006-06-30 01:56:08 -07001204 return -ENODEV;
Alan Cox806c35f2006-01-18 17:44:08 -08001205}
1206
1207/* returns count (>= 0), or negative on error */
1208static int __devinit e752x_init_one(struct pci_dev *pdev,
Douglas Thompson052dfb42007-07-19 01:50:13 -07001209 const struct pci_device_id *ent)
Alan Cox806c35f2006-01-18 17:44:08 -08001210{
Dave Peterson537fba22006-03-26 01:38:40 -08001211 debugf0("%s()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -08001212
1213 /* wake up and enable device */
Dave Jiang203333c2007-07-19 01:50:06 -07001214 if (pci_enable_device(pdev) < 0)
Alan Cox806c35f2006-01-18 17:44:08 -08001215 return -EIO;
Dave Petersone7ecd892006-03-26 01:38:52 -08001216
Alan Cox806c35f2006-01-18 17:44:08 -08001217 return e752x_probe1(pdev, ent->driver_data);
1218}
1219
Alan Cox806c35f2006-01-18 17:44:08 -08001220static void __devexit e752x_remove_one(struct pci_dev *pdev)
1221{
1222 struct mem_ctl_info *mci;
1223 struct e752x_pvt *pvt;
1224
Dave Peterson537fba22006-03-26 01:38:40 -08001225 debugf0("%s()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -08001226
Dave Jiang91b99042007-07-19 01:49:52 -07001227 if (e752x_pci)
1228 edac_pci_release_generic_ctl(e752x_pci);
1229
Doug Thompson37f04582006-06-30 01:56:07 -07001230 if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
Alan Cox806c35f2006-01-18 17:44:08 -08001231 return;
1232
Dave Jiang203333c2007-07-19 01:50:06 -07001233 pvt = (struct e752x_pvt *)mci->pvt_info;
Alan Cox806c35f2006-01-18 17:44:08 -08001234 pci_dev_put(pvt->dev_d0f0);
1235 pci_dev_put(pvt->dev_d0f1);
1236 pci_dev_put(pvt->bridge_ck);
1237 edac_mc_free(mci);
1238}
1239
Alan Cox806c35f2006-01-18 17:44:08 -08001240static const struct pci_device_id e752x_pci_tbl[] __devinitdata = {
Dave Petersone7ecd892006-03-26 01:38:52 -08001241 {
Dave Jiang203333c2007-07-19 01:50:06 -07001242 PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
1243 E7520},
Dave Petersone7ecd892006-03-26 01:38:52 -08001244 {
Dave Jiang203333c2007-07-19 01:50:06 -07001245 PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
1246 E7525},
Dave Petersone7ecd892006-03-26 01:38:52 -08001247 {
Dave Jiang203333c2007-07-19 01:50:06 -07001248 PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
1249 E7320},
Dave Petersone7ecd892006-03-26 01:38:52 -08001250 {
Andrei Konovalov5135b792008-04-29 01:03:13 -07001251 PCI_VEND_DEV(INTEL, 3100_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
1252 I3100},
1253 {
Dave Jiang203333c2007-07-19 01:50:06 -07001254 0,
1255 } /* 0 terminated list. */
Alan Cox806c35f2006-01-18 17:44:08 -08001256};
1257
1258MODULE_DEVICE_TABLE(pci, e752x_pci_tbl);
1259
Alan Cox806c35f2006-01-18 17:44:08 -08001260static struct pci_driver e752x_driver = {
Dave Peterson680cbbb2006-03-26 01:38:41 -08001261 .name = EDAC_MOD_STR,
Randy Dunlap0d38b042006-02-03 03:04:24 -08001262 .probe = e752x_init_one,
1263 .remove = __devexit_p(e752x_remove_one),
1264 .id_table = e752x_pci_tbl,
Alan Cox806c35f2006-01-18 17:44:08 -08001265};
1266
Alan Coxda9bb1d2006-01-18 17:44:13 -08001267static int __init e752x_init(void)
Alan Cox806c35f2006-01-18 17:44:08 -08001268{
1269 int pci_rc;
1270
Dave Peterson537fba22006-03-26 01:38:40 -08001271 debugf3("%s()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -08001272 pci_rc = pci_register_driver(&e752x_driver);
1273 return (pci_rc < 0) ? pci_rc : 0;
1274}
1275
Alan Cox806c35f2006-01-18 17:44:08 -08001276static void __exit e752x_exit(void)
1277{
Dave Peterson537fba22006-03-26 01:38:40 -08001278 debugf3("%s()\n", __func__);
Alan Cox806c35f2006-01-18 17:44:08 -08001279 pci_unregister_driver(&e752x_driver);
1280}
1281
Alan Cox806c35f2006-01-18 17:44:08 -08001282module_init(e752x_init);
1283module_exit(e752x_exit);
1284
1285MODULE_LICENSE("GPL");
1286MODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman\n");
Andrei Konovalov5135b792008-04-29 01:03:13 -07001287MODULE_DESCRIPTION("MC support for Intel e752x/3100 memory controllers");
mark gross96941022006-05-03 19:55:07 -07001288
1289module_param(force_function_unhide, int, 0444);
1290MODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:"
Dave Jiang203333c2007-07-19 01:50:06 -07001291 " 1=force unhide and hope BIOS doesn't fight driver for Dev0:Fun1 access");
Dave Jiangc0d12172007-07-19 01:49:46 -07001292module_param(edac_op_state, int, 0444);
1293MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");