1806c35f5SAlan Cox /*
2806c35f5SAlan Cox * Intel e752x Memory Controller kernel module
3806c35f5SAlan Cox * (C) 2004 Linux Networx (http://lnxi.com)
4806c35f5SAlan Cox * This file may be distributed under the terms of the
5806c35f5SAlan Cox * GNU General Public License.
6806c35f5SAlan Cox *
7805afb69SMauro Carvalho Chehab * Implement support for the e7520, E7525, e7320 and i3100 memory controllers.
8806c35f5SAlan Cox *
9805afb69SMauro Carvalho Chehab * Datasheets:
107d4c1ea2SAlexander A. Klimov * https://www.intel.in/content/www/in/en/chipsets/e7525-memory-controller-hub-datasheet.html
11805afb69SMauro Carvalho Chehab * ftp://download.intel.com/design/intarch/datashts/31345803.pdf
12ce11ce17SMauro Carvalho Chehab *
13806c35f5SAlan Cox * Written by Tom Zimmerman
14806c35f5SAlan Cox *
15806c35f5SAlan Cox * Contributors:
16806c35f5SAlan Cox * Thayne Harbaugh at realmsys.com (?)
17806c35f5SAlan Cox * Wang Zhenyu at intel.com
18806c35f5SAlan Cox * Dave Jiang at mvista.com
19806c35f5SAlan Cox *
20806c35f5SAlan Cox */
21806c35f5SAlan Cox
22806c35f5SAlan Cox #include <linux/module.h>
23806c35f5SAlan Cox #include <linux/init.h>
24806c35f5SAlan Cox #include <linux/pci.h>
25806c35f5SAlan Cox #include <linux/pci_ids.h>
26c0d12172SDave Jiang #include <linux/edac.h>
2778d88e8aSMauro Carvalho Chehab #include "edac_module.h"
28806c35f5SAlan Cox
29929a40ecSDoug Thompson #define EDAC_MOD_STR "e752x_edac"
3037f04581SDoug Thompson
3110d33e9cSDoug Thompson static int report_non_memory_errors;
3296941026Smark gross static int force_function_unhide;
3394ee1cf5SPeter Tyser static int sysbus_parity = -1;
3496941026Smark gross
3591b99041SDave Jiang static struct edac_pci_ctl_info *e752x_pci;
3691b99041SDave Jiang
37537fba28SDave Peterson #define e752x_printk(level, fmt, arg...) \
38537fba28SDave Peterson edac_printk(level, "e752x", fmt, ##arg)
39537fba28SDave Peterson
40537fba28SDave Peterson #define e752x_mc_printk(mci, level, fmt, arg...) \
41537fba28SDave Peterson edac_mc_chipset_printk(mci, level, "e752x", fmt, ##arg)
42537fba28SDave Peterson
43806c35f5SAlan Cox #ifndef PCI_DEVICE_ID_INTEL_7520_0
44806c35f5SAlan Cox #define PCI_DEVICE_ID_INTEL_7520_0 0x3590
45806c35f5SAlan Cox #endif /* PCI_DEVICE_ID_INTEL_7520_0 */
46806c35f5SAlan Cox
47806c35f5SAlan Cox #ifndef PCI_DEVICE_ID_INTEL_7520_1_ERR
48806c35f5SAlan Cox #define PCI_DEVICE_ID_INTEL_7520_1_ERR 0x3591
49806c35f5SAlan Cox #endif /* PCI_DEVICE_ID_INTEL_7520_1_ERR */
50806c35f5SAlan Cox
51806c35f5SAlan Cox #ifndef PCI_DEVICE_ID_INTEL_7525_0
52806c35f5SAlan Cox #define PCI_DEVICE_ID_INTEL_7525_0 0x359E
53806c35f5SAlan Cox #endif /* PCI_DEVICE_ID_INTEL_7525_0 */
54806c35f5SAlan Cox
55806c35f5SAlan Cox #ifndef PCI_DEVICE_ID_INTEL_7525_1_ERR
56806c35f5SAlan Cox #define PCI_DEVICE_ID_INTEL_7525_1_ERR 0x3593
57806c35f5SAlan Cox #endif /* PCI_DEVICE_ID_INTEL_7525_1_ERR */
58806c35f5SAlan Cox
59806c35f5SAlan Cox #ifndef PCI_DEVICE_ID_INTEL_7320_0
60806c35f5SAlan Cox #define PCI_DEVICE_ID_INTEL_7320_0 0x3592
61806c35f5SAlan Cox #endif /* PCI_DEVICE_ID_INTEL_7320_0 */
62806c35f5SAlan Cox
63806c35f5SAlan Cox #ifndef PCI_DEVICE_ID_INTEL_7320_1_ERR
64806c35f5SAlan Cox #define PCI_DEVICE_ID_INTEL_7320_1_ERR 0x3593
65806c35f5SAlan Cox #endif /* PCI_DEVICE_ID_INTEL_7320_1_ERR */
66806c35f5SAlan Cox
675135b797SAndrei Konovalov #ifndef PCI_DEVICE_ID_INTEL_3100_0
685135b797SAndrei Konovalov #define PCI_DEVICE_ID_INTEL_3100_0 0x35B0
695135b797SAndrei Konovalov #endif /* PCI_DEVICE_ID_INTEL_3100_0 */
705135b797SAndrei Konovalov
715135b797SAndrei Konovalov #ifndef PCI_DEVICE_ID_INTEL_3100_1_ERR
725135b797SAndrei Konovalov #define PCI_DEVICE_ID_INTEL_3100_1_ERR 0x35B1
735135b797SAndrei Konovalov #endif /* PCI_DEVICE_ID_INTEL_3100_1_ERR */
745135b797SAndrei Konovalov
75806c35f5SAlan Cox #define E752X_NR_CSROWS 8 /* number of csrows */
76806c35f5SAlan Cox
77806c35f5SAlan Cox /* E752X register addresses - device 0 function 0 */
788004fd2aSPeter Tyser #define E752X_MCHSCRB 0x52 /* Memory Scrub register (16b) */
798004fd2aSPeter Tyser /*
808004fd2aSPeter Tyser * 6:5 Scrub Completion Count
818004fd2aSPeter Tyser * 3:2 Scrub Rate (i3100 only)
828004fd2aSPeter Tyser * 01=fast 10=normal
838004fd2aSPeter Tyser * 1:0 Scrub Mode enable
848004fd2aSPeter Tyser * 00=off 10=on
858004fd2aSPeter Tyser */
86806c35f5SAlan Cox #define E752X_DRB 0x60 /* DRAM row boundary register (8b) */
87806c35f5SAlan Cox #define E752X_DRA 0x70 /* DRAM row attribute register (8b) */
88806c35f5SAlan Cox /*
89806c35f5SAlan Cox * 31:30 Device width row 7
90806c35f5SAlan Cox * 01=x8 10=x4 11=x8 DDR2
91806c35f5SAlan Cox * 27:26 Device width row 6
92806c35f5SAlan Cox * 23:22 Device width row 5
93806c35f5SAlan Cox * 19:20 Device width row 4
94806c35f5SAlan Cox * 15:14 Device width row 3
95806c35f5SAlan Cox * 11:10 Device width row 2
96806c35f5SAlan Cox * 7:6 Device width row 1
97806c35f5SAlan Cox * 3:2 Device width row 0
98806c35f5SAlan Cox */
99806c35f5SAlan Cox #define E752X_DRC 0x7C /* DRAM controller mode reg (32b) */
100806c35f5SAlan Cox /* FIXME:IS THIS RIGHT? */
101806c35f5SAlan Cox /*
102806c35f5SAlan Cox * 22 Number channels 0=1,1=2
103806c35f5SAlan Cox * 19:18 DRB Granularity 32/64MB
104806c35f5SAlan Cox */
105806c35f5SAlan Cox #define E752X_DRM 0x80 /* Dimm mapping register */
106806c35f5SAlan Cox #define E752X_DDRCSR 0x9A /* DDR control and status reg (16b) */
107806c35f5SAlan Cox /*
108806c35f5SAlan Cox * 14:12 1 single A, 2 single B, 3 dual
109806c35f5SAlan Cox */
110806c35f5SAlan Cox #define E752X_TOLM 0xC4 /* DRAM top of low memory reg (16b) */
111806c35f5SAlan Cox #define E752X_REMAPBASE 0xC6 /* DRAM remap base address reg (16b) */
112806c35f5SAlan Cox #define E752X_REMAPLIMIT 0xC8 /* DRAM remap limit address reg (16b) */
113806c35f5SAlan Cox #define E752X_REMAPOFFSET 0xCA /* DRAM remap limit offset reg (16b) */
114806c35f5SAlan Cox
115806c35f5SAlan Cox /* E752X register addresses - device 0 function 1 */
116806c35f5SAlan Cox #define E752X_FERR_GLOBAL 0x40 /* Global first error register (32b) */
117806c35f5SAlan Cox #define E752X_NERR_GLOBAL 0x44 /* Global next error register (32b) */
118806c35f5SAlan Cox #define E752X_HI_FERR 0x50 /* Hub interface first error reg (8b) */
119806c35f5SAlan Cox #define E752X_HI_NERR 0x52 /* Hub interface next error reg (8b) */
120806c35f5SAlan Cox #define E752X_HI_ERRMASK 0x54 /* Hub interface error mask reg (8b) */
121806c35f5SAlan Cox #define E752X_HI_SMICMD 0x5A /* Hub interface SMI command reg (8b) */
122806c35f5SAlan Cox #define E752X_SYSBUS_FERR 0x60 /* System buss first error reg (16b) */
123806c35f5SAlan Cox #define E752X_SYSBUS_NERR 0x62 /* System buss next error reg (16b) */
124806c35f5SAlan Cox #define E752X_SYSBUS_ERRMASK 0x64 /* System buss error mask reg (16b) */
125806c35f5SAlan Cox #define E752X_SYSBUS_SMICMD 0x6A /* System buss SMI command reg (16b) */
126806c35f5SAlan Cox #define E752X_BUF_FERR 0x70 /* Memory buffer first error reg (8b) */
127806c35f5SAlan Cox #define E752X_BUF_NERR 0x72 /* Memory buffer next error reg (8b) */
128806c35f5SAlan Cox #define E752X_BUF_ERRMASK 0x74 /* Memory buffer error mask reg (8b) */
12910d33e9cSDoug Thompson #define E752X_BUF_SMICMD 0x7A /* Memory buffer SMI cmd reg (8b) */
130806c35f5SAlan Cox #define E752X_DRAM_FERR 0x80 /* DRAM first error register (16b) */
131806c35f5SAlan Cox #define E752X_DRAM_NERR 0x82 /* DRAM next error register (16b) */
132806c35f5SAlan Cox #define E752X_DRAM_ERRMASK 0x84 /* DRAM error mask register (8b) */
133806c35f5SAlan Cox #define E752X_DRAM_SMICMD 0x8A /* DRAM SMI command register (8b) */
134806c35f5SAlan Cox #define E752X_DRAM_RETR_ADD 0xAC /* DRAM Retry address register (32b) */
135806c35f5SAlan Cox #define E752X_DRAM_SEC1_ADD 0xA0 /* DRAM first correctable memory */
136806c35f5SAlan Cox /* error address register (32b) */
137806c35f5SAlan Cox /*
138806c35f5SAlan Cox * 31 Reserved
13910d33e9cSDoug Thompson * 30:2 CE address (64 byte block 34:6
140806c35f5SAlan Cox * 1 Reserved
141806c35f5SAlan Cox * 0 HiLoCS
142806c35f5SAlan Cox */
143806c35f5SAlan Cox #define E752X_DRAM_SEC2_ADD 0xC8 /* DRAM first correctable memory */
144806c35f5SAlan Cox /* error address register (32b) */
145806c35f5SAlan Cox /*
146806c35f5SAlan Cox * 31 Reserved
147806c35f5SAlan Cox * 30:2 CE address (64 byte block 34:6)
148806c35f5SAlan Cox * 1 Reserved
149806c35f5SAlan Cox * 0 HiLoCS
150806c35f5SAlan Cox */
151806c35f5SAlan Cox #define E752X_DRAM_DED_ADD 0xA4 /* DRAM first uncorrectable memory */
152806c35f5SAlan Cox /* error address register (32b) */
153806c35f5SAlan Cox /*
154806c35f5SAlan Cox * 31 Reserved
155806c35f5SAlan Cox * 30:2 CE address (64 byte block 34:6)
156806c35f5SAlan Cox * 1 Reserved
157806c35f5SAlan Cox * 0 HiLoCS
158806c35f5SAlan Cox */
15910d33e9cSDoug Thompson #define E752X_DRAM_SCRB_ADD 0xA8 /* DRAM 1st uncorrectable scrub mem */
160806c35f5SAlan Cox /* error address register (32b) */
161806c35f5SAlan Cox /*
162806c35f5SAlan Cox * 31 Reserved
16310d33e9cSDoug Thompson * 30:2 CE address (64 byte block 34:6
164806c35f5SAlan Cox * 1 Reserved
165806c35f5SAlan Cox * 0 HiLoCS
166806c35f5SAlan Cox */
167806c35f5SAlan Cox #define E752X_DRAM_SEC1_SYNDROME 0xC4 /* DRAM first correctable memory */
168806c35f5SAlan Cox /* error syndrome register (16b) */
169806c35f5SAlan Cox #define E752X_DRAM_SEC2_SYNDROME 0xC6 /* DRAM second correctable memory */
170806c35f5SAlan Cox /* error syndrome register (16b) */
171806c35f5SAlan Cox #define E752X_DEVPRES1 0xF4 /* Device Present 1 register (8b) */
172806c35f5SAlan Cox
1735135b797SAndrei Konovalov /* 3100 IMCH specific register addresses - device 0 function 1 */
1745135b797SAndrei Konovalov #define I3100_NSI_FERR 0x48 /* NSI first error reg (32b) */
1755135b797SAndrei Konovalov #define I3100_NSI_NERR 0x4C /* NSI next error reg (32b) */
1765135b797SAndrei Konovalov #define I3100_NSI_SMICMD 0x54 /* NSI SMI command register (32b) */
1775135b797SAndrei Konovalov #define I3100_NSI_EMASK 0x90 /* NSI error mask register (32b) */
1785135b797SAndrei Konovalov
179806c35f5SAlan Cox /* ICH5R register addresses - device 30 function 0 */
180806c35f5SAlan Cox #define ICH5R_PCI_STAT 0x06 /* PCI status register (16b) */
181806c35f5SAlan Cox #define ICH5R_PCI_2ND_STAT 0x1E /* PCI status secondary reg (16b) */
182806c35f5SAlan Cox #define ICH5R_PCI_BRIDGE_CTL 0x3E /* PCI bridge control register (16b) */
183806c35f5SAlan Cox
184806c35f5SAlan Cox enum e752x_chips {
185806c35f5SAlan Cox E7520 = 0,
186806c35f5SAlan Cox E7525 = 1,
1875135b797SAndrei Konovalov E7320 = 2,
1885135b797SAndrei Konovalov I3100 = 3
189806c35f5SAlan Cox };
190806c35f5SAlan Cox
191805afb69SMauro Carvalho Chehab /*
192805afb69SMauro Carvalho Chehab * Those chips Support single-rank and dual-rank memories only.
193805afb69SMauro Carvalho Chehab *
194805afb69SMauro Carvalho Chehab * On e752x chips, the odd rows are present only on dual-rank memories.
195805afb69SMauro Carvalho Chehab * Dividing the rank by two will provide the dimm#
196805afb69SMauro Carvalho Chehab *
197805afb69SMauro Carvalho Chehab * i3100 MC has a different mapping: it supports only 4 ranks.
198805afb69SMauro Carvalho Chehab *
199805afb69SMauro Carvalho Chehab * The mapping is (from 1 to n):
200805afb69SMauro Carvalho Chehab * slot single-ranked double-ranked
201805afb69SMauro Carvalho Chehab * dimm #1 -> rank #4 NA
202805afb69SMauro Carvalho Chehab * dimm #2 -> rank #3 NA
203805afb69SMauro Carvalho Chehab * dimm #3 -> rank #2 Ranks 2 and 3
204805afb69SMauro Carvalho Chehab * dimm #4 -> rank $1 Ranks 1 and 4
205805afb69SMauro Carvalho Chehab *
206805afb69SMauro Carvalho Chehab * FIXME: The current mapping for i3100 considers that it supports up to 8
207805afb69SMauro Carvalho Chehab * ranks/chanel, but datasheet says that the MC supports only 4 ranks.
208805afb69SMauro Carvalho Chehab */
209805afb69SMauro Carvalho Chehab
210806c35f5SAlan Cox struct e752x_pvt {
211806c35f5SAlan Cox struct pci_dev *dev_d0f0;
212806c35f5SAlan Cox struct pci_dev *dev_d0f1;
213806c35f5SAlan Cox u32 tolm;
214806c35f5SAlan Cox u32 remapbase;
215806c35f5SAlan Cox u32 remaplimit;
216806c35f5SAlan Cox int mc_symmetric;
217806c35f5SAlan Cox u8 map[8];
218806c35f5SAlan Cox int map_type;
219806c35f5SAlan Cox const struct e752x_dev_info *dev_info;
220806c35f5SAlan Cox };
221806c35f5SAlan Cox
222806c35f5SAlan Cox struct e752x_dev_info {
223806c35f5SAlan Cox u16 err_dev;
2243847bcccSDave Peterson u16 ctl_dev;
225806c35f5SAlan Cox const char *ctl_name;
226806c35f5SAlan Cox };
227806c35f5SAlan Cox
228806c35f5SAlan Cox struct e752x_error_info {
229806c35f5SAlan Cox u32 ferr_global;
230806c35f5SAlan Cox u32 nerr_global;
2315135b797SAndrei Konovalov u32 nsi_ferr; /* 3100 only */
2325135b797SAndrei Konovalov u32 nsi_nerr; /* 3100 only */
2335135b797SAndrei Konovalov u8 hi_ferr; /* all but 3100 */
2345135b797SAndrei Konovalov u8 hi_nerr; /* all but 3100 */
235806c35f5SAlan Cox u16 sysbus_ferr;
236806c35f5SAlan Cox u16 sysbus_nerr;
237806c35f5SAlan Cox u8 buf_ferr;
238806c35f5SAlan Cox u8 buf_nerr;
239806c35f5SAlan Cox u16 dram_ferr;
240806c35f5SAlan Cox u16 dram_nerr;
241806c35f5SAlan Cox u32 dram_sec1_add;
242806c35f5SAlan Cox u32 dram_sec2_add;
243806c35f5SAlan Cox u16 dram_sec1_syndrome;
244806c35f5SAlan Cox u16 dram_sec2_syndrome;
245806c35f5SAlan Cox u32 dram_ded_add;
246806c35f5SAlan Cox u32 dram_scrb_add;
247806c35f5SAlan Cox u32 dram_retr_add;
248806c35f5SAlan Cox };
249806c35f5SAlan Cox
250806c35f5SAlan Cox static const struct e752x_dev_info e752x_devs[] = {
251806c35f5SAlan Cox [E7520] = {
252806c35f5SAlan Cox .err_dev = PCI_DEVICE_ID_INTEL_7520_1_ERR,
2533847bcccSDave Peterson .ctl_dev = PCI_DEVICE_ID_INTEL_7520_0,
254203333cbSDave Jiang .ctl_name = "E7520"},
255806c35f5SAlan Cox [E7525] = {
256806c35f5SAlan Cox .err_dev = PCI_DEVICE_ID_INTEL_7525_1_ERR,
2573847bcccSDave Peterson .ctl_dev = PCI_DEVICE_ID_INTEL_7525_0,
258203333cbSDave Jiang .ctl_name = "E7525"},
259806c35f5SAlan Cox [E7320] = {
260806c35f5SAlan Cox .err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR,
2613847bcccSDave Peterson .ctl_dev = PCI_DEVICE_ID_INTEL_7320_0,
262203333cbSDave Jiang .ctl_name = "E7320"},
2635135b797SAndrei Konovalov [I3100] = {
2645135b797SAndrei Konovalov .err_dev = PCI_DEVICE_ID_INTEL_3100_1_ERR,
2655135b797SAndrei Konovalov .ctl_dev = PCI_DEVICE_ID_INTEL_3100_0,
2665135b797SAndrei Konovalov .ctl_name = "3100"},
267806c35f5SAlan Cox };
268806c35f5SAlan Cox
2698004fd2aSPeter Tyser /* Valid scrub rates for the e752x/3100 hardware memory scrubber. We
2708004fd2aSPeter Tyser * map the scrubbing bandwidth to a hardware register value. The 'set'
2718004fd2aSPeter Tyser * operation finds the 'matching or higher value'. Note that scrubbing
2728004fd2aSPeter Tyser * on the e752x can only be enabled/disabled. The 3100 supports
2738004fd2aSPeter Tyser * a normal and fast mode.
2748004fd2aSPeter Tyser */
2758004fd2aSPeter Tyser
2768004fd2aSPeter Tyser #define SDRATE_EOT 0xFFFFFFFF
2778004fd2aSPeter Tyser
2788004fd2aSPeter Tyser struct scrubrate {
2798004fd2aSPeter Tyser u32 bandwidth; /* bandwidth consumed by scrubbing in bytes/sec */
2808004fd2aSPeter Tyser u16 scrubval; /* register value for scrub rate */
2818004fd2aSPeter Tyser };
2828004fd2aSPeter Tyser
2838004fd2aSPeter Tyser /* Rate below assumes same performance as i3100 using PC3200 DDR2 in
2848004fd2aSPeter Tyser * normal mode. e752x bridges don't support choosing normal or fast mode,
2858004fd2aSPeter Tyser * so the scrubbing bandwidth value isn't all that important - scrubbing is
2868004fd2aSPeter Tyser * either on or off.
2878004fd2aSPeter Tyser */
2888004fd2aSPeter Tyser static const struct scrubrate scrubrates_e752x[] = {
2898004fd2aSPeter Tyser {0, 0x00}, /* Scrubbing Off */
2908004fd2aSPeter Tyser {500000, 0x02}, /* Scrubbing On */
2918004fd2aSPeter Tyser {SDRATE_EOT, 0x00} /* End of Table */
2928004fd2aSPeter Tyser };
2938004fd2aSPeter Tyser
2948004fd2aSPeter Tyser /* Fast mode: 2 GByte PC3200 DDR2 scrubbed in 33s = 63161283 bytes/s
2958004fd2aSPeter Tyser * Normal mode: 125 (32000 / 256) times slower than fast mode.
2968004fd2aSPeter Tyser */
2978004fd2aSPeter Tyser static const struct scrubrate scrubrates_i3100[] = {
2988004fd2aSPeter Tyser {0, 0x00}, /* Scrubbing Off */
2998004fd2aSPeter Tyser {500000, 0x0a}, /* Normal mode - 32k clocks */
3008004fd2aSPeter Tyser {62500000, 0x06}, /* Fast mode - 256 clocks */
3018004fd2aSPeter Tyser {SDRATE_EOT, 0x00} /* End of Table */
3028004fd2aSPeter Tyser };
3038004fd2aSPeter Tyser
ctl_page_to_phys(struct mem_ctl_info * mci,unsigned long page)304806c35f5SAlan Cox static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
305806c35f5SAlan Cox unsigned long page)
306806c35f5SAlan Cox {
307806c35f5SAlan Cox u32 remap;
308806c35f5SAlan Cox struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
309806c35f5SAlan Cox
310956b9ba1SJoe Perches edac_dbg(3, "\n");
311806c35f5SAlan Cox
312806c35f5SAlan Cox if (page < pvt->tolm)
313806c35f5SAlan Cox return page;
314e7ecd891SDave Peterson
315806c35f5SAlan Cox if ((page >= 0x100000) && (page < pvt->remapbase))
316806c35f5SAlan Cox return page;
317e7ecd891SDave Peterson
318806c35f5SAlan Cox remap = (page - pvt->tolm) + pvt->remapbase;
319e7ecd891SDave Peterson
320806c35f5SAlan Cox if (remap < pvt->remaplimit)
321806c35f5SAlan Cox return remap;
322e7ecd891SDave Peterson
323537fba28SDave Peterson e752x_printk(KERN_ERR, "Invalid page %lx - out of range\n", page);
324806c35f5SAlan Cox return pvt->tolm - 1;
325806c35f5SAlan Cox }
326806c35f5SAlan Cox
do_process_ce(struct mem_ctl_info * mci,u16 error_one,u32 sec1_add,u16 sec1_syndrome)327806c35f5SAlan Cox static void do_process_ce(struct mem_ctl_info *mci, u16 error_one,
328806c35f5SAlan Cox u32 sec1_add, u16 sec1_syndrome)
329806c35f5SAlan Cox {
330806c35f5SAlan Cox u32 page;
331806c35f5SAlan Cox int row;
332806c35f5SAlan Cox int channel;
333806c35f5SAlan Cox int i;
334806c35f5SAlan Cox struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
335806c35f5SAlan Cox
336956b9ba1SJoe Perches edac_dbg(3, "\n");
337806c35f5SAlan Cox
338806c35f5SAlan Cox /* convert the addr to 4k page */
339806c35f5SAlan Cox page = sec1_add >> (PAGE_SHIFT - 4);
340806c35f5SAlan Cox
341806c35f5SAlan Cox /* FIXME - check for -1 */
342806c35f5SAlan Cox if (pvt->mc_symmetric) {
343806c35f5SAlan Cox /* chip select are bits 14 & 13 */
344806c35f5SAlan Cox row = ((page >> 1) & 3);
345537fba28SDave Peterson e752x_printk(KERN_WARNING,
346e7ecd891SDave Peterson "Test row %d Table %d %d %d %d %d %d %d %d\n", row,
347e7ecd891SDave Peterson pvt->map[0], pvt->map[1], pvt->map[2], pvt->map[3],
348203333cbSDave Jiang pvt->map[4], pvt->map[5], pvt->map[6],
349203333cbSDave Jiang pvt->map[7]);
350806c35f5SAlan Cox
351806c35f5SAlan Cox /* test for channel remapping */
352806c35f5SAlan Cox for (i = 0; i < 8; i++) {
353806c35f5SAlan Cox if (pvt->map[i] == row)
354806c35f5SAlan Cox break;
355806c35f5SAlan Cox }
356e7ecd891SDave Peterson
357537fba28SDave Peterson e752x_printk(KERN_WARNING, "Test computed row %d\n", i);
358e7ecd891SDave Peterson
359806c35f5SAlan Cox if (i < 8)
360806c35f5SAlan Cox row = i;
361806c35f5SAlan Cox else
362537fba28SDave Peterson e752x_mc_printk(mci, KERN_WARNING,
363203333cbSDave Jiang "row %d not found in remap table\n",
364203333cbSDave Jiang row);
365806c35f5SAlan Cox } else
366806c35f5SAlan Cox row = edac_mc_find_csrow_by_page(mci, page);
367e7ecd891SDave Peterson
368806c35f5SAlan Cox /* 0 = channel A, 1 = channel B */
369806c35f5SAlan Cox channel = !(error_one & 1);
370806c35f5SAlan Cox
37184db003fSMike Chan /* e752x mc reads 34:6 of the DRAM linear address */
3729eb07a7fSMauro Carvalho Chehab edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
373ce11ce17SMauro Carvalho Chehab page, offset_in_page(sec1_add << 4), sec1_syndrome,
374ce11ce17SMauro Carvalho Chehab row, channel, -1,
37503f7eae8SMauro Carvalho Chehab "e752x CE", "");
376806c35f5SAlan Cox }
377806c35f5SAlan Cox
process_ce(struct mem_ctl_info * mci,u16 error_one,u32 sec1_add,u16 sec1_syndrome,int * error_found,int handle_error)378806c35f5SAlan Cox static inline void process_ce(struct mem_ctl_info *mci, u16 error_one,
379806c35f5SAlan Cox u32 sec1_add, u16 sec1_syndrome, int *error_found,
380806c35f5SAlan Cox int handle_error)
381806c35f5SAlan Cox {
382806c35f5SAlan Cox *error_found = 1;
383806c35f5SAlan Cox
384806c35f5SAlan Cox if (handle_error)
385806c35f5SAlan Cox do_process_ce(mci, error_one, sec1_add, sec1_syndrome);
386806c35f5SAlan Cox }
387806c35f5SAlan Cox
do_process_ue(struct mem_ctl_info * mci,u16 error_one,u32 ded_add,u32 scrb_add)388e7ecd891SDave Peterson static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
389e7ecd891SDave Peterson u32 ded_add, u32 scrb_add)
390806c35f5SAlan Cox {
391806c35f5SAlan Cox u32 error_2b, block_page;
392806c35f5SAlan Cox int row;
393806c35f5SAlan Cox struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
394806c35f5SAlan Cox
395956b9ba1SJoe Perches edac_dbg(3, "\n");
396806c35f5SAlan Cox
397806c35f5SAlan Cox if (error_one & 0x0202) {
398806c35f5SAlan Cox error_2b = ded_add;
399e7ecd891SDave Peterson
400806c35f5SAlan Cox /* convert to 4k address */
401806c35f5SAlan Cox block_page = error_2b >> (PAGE_SHIFT - 4);
402e7ecd891SDave Peterson
403806c35f5SAlan Cox row = pvt->mc_symmetric ?
404806c35f5SAlan Cox /* chip select are bits 14 & 13 */
405806c35f5SAlan Cox ((block_page >> 1) & 3) :
406806c35f5SAlan Cox edac_mc_find_csrow_by_page(mci, block_page);
407e7ecd891SDave Peterson
40884db003fSMike Chan /* e752x mc reads 34:6 of the DRAM linear address */
4099eb07a7fSMauro Carvalho Chehab edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
410ce11ce17SMauro Carvalho Chehab block_page,
411ce11ce17SMauro Carvalho Chehab offset_in_page(error_2b << 4), 0,
412ce11ce17SMauro Carvalho Chehab row, -1, -1,
41303f7eae8SMauro Carvalho Chehab "e752x UE from Read", "");
414ce11ce17SMauro Carvalho Chehab
415806c35f5SAlan Cox }
416806c35f5SAlan Cox if (error_one & 0x0404) {
417806c35f5SAlan Cox error_2b = scrb_add;
418e7ecd891SDave Peterson
419806c35f5SAlan Cox /* convert to 4k address */
420806c35f5SAlan Cox block_page = error_2b >> (PAGE_SHIFT - 4);
421e7ecd891SDave Peterson
422806c35f5SAlan Cox row = pvt->mc_symmetric ?
423806c35f5SAlan Cox /* chip select are bits 14 & 13 */
424806c35f5SAlan Cox ((block_page >> 1) & 3) :
425806c35f5SAlan Cox edac_mc_find_csrow_by_page(mci, block_page);
426e7ecd891SDave Peterson
42784db003fSMike Chan /* e752x mc reads 34:6 of the DRAM linear address */
4289eb07a7fSMauro Carvalho Chehab edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
429ce11ce17SMauro Carvalho Chehab block_page,
430ce11ce17SMauro Carvalho Chehab offset_in_page(error_2b << 4), 0,
431ce11ce17SMauro Carvalho Chehab row, -1, -1,
43203f7eae8SMauro Carvalho Chehab "e752x UE from Scruber", "");
433806c35f5SAlan Cox }
434806c35f5SAlan Cox }
435806c35f5SAlan Cox
process_ue(struct mem_ctl_info * mci,u16 error_one,u32 ded_add,u32 scrb_add,int * error_found,int handle_error)436806c35f5SAlan Cox static inline void process_ue(struct mem_ctl_info *mci, u16 error_one,
437203333cbSDave Jiang u32 ded_add, u32 scrb_add, int *error_found,
438203333cbSDave Jiang int handle_error)
439806c35f5SAlan Cox {
440806c35f5SAlan Cox *error_found = 1;
441806c35f5SAlan Cox
442806c35f5SAlan Cox if (handle_error)
443806c35f5SAlan Cox do_process_ue(mci, error_one, ded_add, scrb_add);
444806c35f5SAlan Cox }
445806c35f5SAlan Cox
process_ue_no_info_wr(struct mem_ctl_info * mci,int * error_found,int handle_error)446806c35f5SAlan Cox static inline void process_ue_no_info_wr(struct mem_ctl_info *mci,
447806c35f5SAlan Cox int *error_found, int handle_error)
448806c35f5SAlan Cox {
449806c35f5SAlan Cox *error_found = 1;
450806c35f5SAlan Cox
451806c35f5SAlan Cox if (!handle_error)
452806c35f5SAlan Cox return;
453806c35f5SAlan Cox
454956b9ba1SJoe Perches edac_dbg(3, "\n");
4559eb07a7fSMauro Carvalho Chehab edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0,
456ce11ce17SMauro Carvalho Chehab -1, -1, -1,
45703f7eae8SMauro Carvalho Chehab "e752x UE log memory write", "");
458806c35f5SAlan Cox }
459806c35f5SAlan Cox
do_process_ded_retry(struct mem_ctl_info * mci,u16 error,u32 retry_add)460806c35f5SAlan Cox static void do_process_ded_retry(struct mem_ctl_info *mci, u16 error,
461806c35f5SAlan Cox u32 retry_add)
462806c35f5SAlan Cox {
463806c35f5SAlan Cox u32 error_1b, page;
464806c35f5SAlan Cox int row;
465806c35f5SAlan Cox struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
466806c35f5SAlan Cox
467806c35f5SAlan Cox error_1b = retry_add;
468806c35f5SAlan Cox page = error_1b >> (PAGE_SHIFT - 4); /* convert the addr to 4k page */
46910d33e9cSDoug Thompson
47010d33e9cSDoug Thompson /* chip select are bits 14 & 13 */
47110d33e9cSDoug Thompson row = pvt->mc_symmetric ? ((page >> 1) & 3) :
472806c35f5SAlan Cox edac_mc_find_csrow_by_page(mci, page);
47310d33e9cSDoug Thompson
474537fba28SDave Peterson e752x_mc_printk(mci, KERN_WARNING,
475537fba28SDave Peterson "CE page 0x%lx, row %d : Memory read retry\n",
476537fba28SDave Peterson (long unsigned int)page, row);
477806c35f5SAlan Cox }
478806c35f5SAlan Cox
process_ded_retry(struct mem_ctl_info * mci,u16 error,u32 retry_add,int * error_found,int handle_error)479806c35f5SAlan Cox static inline void process_ded_retry(struct mem_ctl_info *mci, u16 error,
480203333cbSDave Jiang u32 retry_add, int *error_found,
481203333cbSDave Jiang int handle_error)
482806c35f5SAlan Cox {
483806c35f5SAlan Cox *error_found = 1;
484806c35f5SAlan Cox
485806c35f5SAlan Cox if (handle_error)
486806c35f5SAlan Cox do_process_ded_retry(mci, error, retry_add);
487806c35f5SAlan Cox }
488806c35f5SAlan Cox
process_threshold_ce(struct mem_ctl_info * mci,u16 error,int * error_found,int handle_error)489806c35f5SAlan Cox static inline void process_threshold_ce(struct mem_ctl_info *mci, u16 error,
490806c35f5SAlan Cox int *error_found, int handle_error)
491806c35f5SAlan Cox {
492806c35f5SAlan Cox *error_found = 1;
493806c35f5SAlan Cox
494806c35f5SAlan Cox if (handle_error)
495537fba28SDave Peterson e752x_mc_printk(mci, KERN_WARNING, "Memory threshold CE\n");
496806c35f5SAlan Cox }
497806c35f5SAlan Cox
498da9bb1d2SAlan Cox static char *global_message[11] = {
49910d33e9cSDoug Thompson "PCI Express C1",
50010d33e9cSDoug Thompson "PCI Express C",
50110d33e9cSDoug Thompson "PCI Express B1",
50210d33e9cSDoug Thompson "PCI Express B",
50310d33e9cSDoug Thompson "PCI Express A1",
50410d33e9cSDoug Thompson "PCI Express A",
50510d33e9cSDoug Thompson "DMA Controller",
50610d33e9cSDoug Thompson "HUB or NS Interface",
50710d33e9cSDoug Thompson "System Bus",
50810d33e9cSDoug Thompson "DRAM Controller", /* 9th entry */
50910d33e9cSDoug Thompson "Internal Buffer"
510806c35f5SAlan Cox };
511806c35f5SAlan Cox
51210d33e9cSDoug Thompson #define DRAM_ENTRY 9
51310d33e9cSDoug Thompson
514da9bb1d2SAlan Cox static char *fatal_message[2] = { "Non-Fatal ", "Fatal " };
515806c35f5SAlan Cox
do_global_error(int fatal,u32 errors)516806c35f5SAlan Cox static void do_global_error(int fatal, u32 errors)
517806c35f5SAlan Cox {
518806c35f5SAlan Cox int i;
519806c35f5SAlan Cox
520806c35f5SAlan Cox for (i = 0; i < 11; i++) {
52110d33e9cSDoug Thompson if (errors & (1 << i)) {
52210d33e9cSDoug Thompson /* If the error is from DRAM Controller OR
52310d33e9cSDoug Thompson * we are to report ALL errors, then
52410d33e9cSDoug Thompson * report the error
52510d33e9cSDoug Thompson */
52610d33e9cSDoug Thompson if ((i == DRAM_ENTRY) || report_non_memory_errors)
527537fba28SDave Peterson e752x_printk(KERN_WARNING, "%sError %s\n",
52810d33e9cSDoug Thompson fatal_message[fatal],
52910d33e9cSDoug Thompson global_message[i]);
53010d33e9cSDoug Thompson }
531806c35f5SAlan Cox }
532806c35f5SAlan Cox }
533806c35f5SAlan Cox
global_error(int fatal,u32 errors,int * error_found,int handle_error)534806c35f5SAlan Cox static inline void global_error(int fatal, u32 errors, int *error_found,
535806c35f5SAlan Cox int handle_error)
536806c35f5SAlan Cox {
537806c35f5SAlan Cox *error_found = 1;
538806c35f5SAlan Cox
539806c35f5SAlan Cox if (handle_error)
540806c35f5SAlan Cox do_global_error(fatal, errors);
541806c35f5SAlan Cox }
542806c35f5SAlan Cox
543da9bb1d2SAlan Cox static char *hub_message[7] = {
544806c35f5SAlan Cox "HI Address or Command Parity", "HI Illegal Access",
545806c35f5SAlan Cox "HI Internal Parity", "Out of Range Access",
546806c35f5SAlan Cox "HI Data Parity", "Enhanced Config Access",
547806c35f5SAlan Cox "Hub Interface Target Abort"
548806c35f5SAlan Cox };
549806c35f5SAlan Cox
do_hub_error(int fatal,u8 errors)550806c35f5SAlan Cox static void do_hub_error(int fatal, u8 errors)
551806c35f5SAlan Cox {
552806c35f5SAlan Cox int i;
553806c35f5SAlan Cox
554806c35f5SAlan Cox for (i = 0; i < 7; i++) {
555806c35f5SAlan Cox if (errors & (1 << i))
556537fba28SDave Peterson e752x_printk(KERN_WARNING, "%sError %s\n",
557806c35f5SAlan Cox fatal_message[fatal], hub_message[i]);
558806c35f5SAlan Cox }
559806c35f5SAlan Cox }
560806c35f5SAlan Cox
hub_error(int fatal,u8 errors,int * error_found,int handle_error)561806c35f5SAlan Cox static inline void hub_error(int fatal, u8 errors, int *error_found,
562806c35f5SAlan Cox int handle_error)
563806c35f5SAlan Cox {
564806c35f5SAlan Cox *error_found = 1;
565806c35f5SAlan Cox
566806c35f5SAlan Cox if (handle_error)
567806c35f5SAlan Cox do_hub_error(fatal, errors);
568806c35f5SAlan Cox }
569806c35f5SAlan Cox
5705135b797SAndrei Konovalov #define NSI_FATAL_MASK 0x0c080081
5715135b797SAndrei Konovalov #define NSI_NON_FATAL_MASK 0x23a0ba64
5725135b797SAndrei Konovalov #define NSI_ERR_MASK (NSI_FATAL_MASK | NSI_NON_FATAL_MASK)
5735135b797SAndrei Konovalov
5745135b797SAndrei Konovalov static char *nsi_message[30] = {
5755135b797SAndrei Konovalov "NSI Link Down", /* NSI_FERR/NSI_NERR bit 0, fatal error */
5765135b797SAndrei Konovalov "", /* reserved */
5775135b797SAndrei Konovalov "NSI Parity Error", /* bit 2, non-fatal */
5785135b797SAndrei Konovalov "", /* reserved */
5795135b797SAndrei Konovalov "", /* reserved */
5805135b797SAndrei Konovalov "Correctable Error Message", /* bit 5, non-fatal */
5815135b797SAndrei Konovalov "Non-Fatal Error Message", /* bit 6, non-fatal */
5825135b797SAndrei Konovalov "Fatal Error Message", /* bit 7, fatal */
5835135b797SAndrei Konovalov "", /* reserved */
5845135b797SAndrei Konovalov "Receiver Error", /* bit 9, non-fatal */
5855135b797SAndrei Konovalov "", /* reserved */
5865135b797SAndrei Konovalov "Bad TLP", /* bit 11, non-fatal */
5875135b797SAndrei Konovalov "Bad DLLP", /* bit 12, non-fatal */
5885135b797SAndrei Konovalov "REPLAY_NUM Rollover", /* bit 13, non-fatal */
5895135b797SAndrei Konovalov "", /* reserved */
5905135b797SAndrei Konovalov "Replay Timer Timeout", /* bit 15, non-fatal */
5915135b797SAndrei Konovalov "", /* reserved */
5925135b797SAndrei Konovalov "", /* reserved */
5935135b797SAndrei Konovalov "", /* reserved */
5945135b797SAndrei Konovalov "Data Link Protocol Error", /* bit 19, fatal */
5955135b797SAndrei Konovalov "", /* reserved */
5965135b797SAndrei Konovalov "Poisoned TLP", /* bit 21, non-fatal */
5975135b797SAndrei Konovalov "", /* reserved */
5985135b797SAndrei Konovalov "Completion Timeout", /* bit 23, non-fatal */
5995135b797SAndrei Konovalov "Completer Abort", /* bit 24, non-fatal */
6005135b797SAndrei Konovalov "Unexpected Completion", /* bit 25, non-fatal */
6015135b797SAndrei Konovalov "Receiver Overflow", /* bit 26, fatal */
6025135b797SAndrei Konovalov "Malformed TLP", /* bit 27, fatal */
6035135b797SAndrei Konovalov "", /* reserved */
6045135b797SAndrei Konovalov "Unsupported Request" /* bit 29, non-fatal */
6055135b797SAndrei Konovalov };
6065135b797SAndrei Konovalov
do_nsi_error(int fatal,u32 errors)6075135b797SAndrei Konovalov static void do_nsi_error(int fatal, u32 errors)
6085135b797SAndrei Konovalov {
6095135b797SAndrei Konovalov int i;
6105135b797SAndrei Konovalov
6115135b797SAndrei Konovalov for (i = 0; i < 30; i++) {
6125135b797SAndrei Konovalov if (errors & (1 << i))
6135135b797SAndrei Konovalov printk(KERN_WARNING "%sError %s\n",
6145135b797SAndrei Konovalov fatal_message[fatal], nsi_message[i]);
6155135b797SAndrei Konovalov }
6165135b797SAndrei Konovalov }
6175135b797SAndrei Konovalov
nsi_error(int fatal,u32 errors,int * error_found,int handle_error)6185135b797SAndrei Konovalov static inline void nsi_error(int fatal, u32 errors, int *error_found,
6195135b797SAndrei Konovalov int handle_error)
6205135b797SAndrei Konovalov {
6215135b797SAndrei Konovalov *error_found = 1;
6225135b797SAndrei Konovalov
6235135b797SAndrei Konovalov if (handle_error)
6245135b797SAndrei Konovalov do_nsi_error(fatal, errors);
6255135b797SAndrei Konovalov }
6265135b797SAndrei Konovalov
627da9bb1d2SAlan Cox static char *membuf_message[4] = {
628806c35f5SAlan Cox "Internal PMWB to DRAM parity",
629806c35f5SAlan Cox "Internal PMWB to System Bus Parity",
630806c35f5SAlan Cox "Internal System Bus or IO to PMWB Parity",
631806c35f5SAlan Cox "Internal DRAM to PMWB Parity"
632806c35f5SAlan Cox };
633806c35f5SAlan Cox
do_membuf_error(u8 errors)634806c35f5SAlan Cox static void do_membuf_error(u8 errors)
635806c35f5SAlan Cox {
636806c35f5SAlan Cox int i;
637806c35f5SAlan Cox
638806c35f5SAlan Cox for (i = 0; i < 4; i++) {
639806c35f5SAlan Cox if (errors & (1 << i))
640537fba28SDave Peterson e752x_printk(KERN_WARNING, "Non-Fatal Error %s\n",
641806c35f5SAlan Cox membuf_message[i]);
642806c35f5SAlan Cox }
643806c35f5SAlan Cox }
644806c35f5SAlan Cox
membuf_error(u8 errors,int * error_found,int handle_error)645806c35f5SAlan Cox static inline void membuf_error(u8 errors, int *error_found, int handle_error)
646806c35f5SAlan Cox {
647806c35f5SAlan Cox *error_found = 1;
648806c35f5SAlan Cox
649806c35f5SAlan Cox if (handle_error)
650806c35f5SAlan Cox do_membuf_error(errors);
651806c35f5SAlan Cox }
652806c35f5SAlan Cox
653e009356fSDave Peterson static char *sysbus_message[10] = {
654806c35f5SAlan Cox "Addr or Request Parity",
655806c35f5SAlan Cox "Data Strobe Glitch",
656806c35f5SAlan Cox "Addr Strobe Glitch",
657806c35f5SAlan Cox "Data Parity",
658806c35f5SAlan Cox "Addr Above TOM",
659806c35f5SAlan Cox "Non DRAM Lock Error",
660806c35f5SAlan Cox "MCERR", "BINIT",
661806c35f5SAlan Cox "Memory Parity",
662806c35f5SAlan Cox "IO Subsystem Parity"
663806c35f5SAlan Cox };
664806c35f5SAlan Cox
do_sysbus_error(int fatal,u32 errors)665806c35f5SAlan Cox static void do_sysbus_error(int fatal, u32 errors)
666806c35f5SAlan Cox {
667806c35f5SAlan Cox int i;
668806c35f5SAlan Cox
669806c35f5SAlan Cox for (i = 0; i < 10; i++) {
670806c35f5SAlan Cox if (errors & (1 << i))
671537fba28SDave Peterson e752x_printk(KERN_WARNING, "%sError System Bus %s\n",
672e009356fSDave Peterson fatal_message[fatal], sysbus_message[i]);
673806c35f5SAlan Cox }
674806c35f5SAlan Cox }
675806c35f5SAlan Cox
sysbus_error(int fatal,u32 errors,int * error_found,int handle_error)676806c35f5SAlan Cox static inline void sysbus_error(int fatal, u32 errors, int *error_found,
677806c35f5SAlan Cox int handle_error)
678806c35f5SAlan Cox {
679806c35f5SAlan Cox *error_found = 1;
680806c35f5SAlan Cox
681806c35f5SAlan Cox if (handle_error)
682806c35f5SAlan Cox do_sysbus_error(fatal, errors);
683806c35f5SAlan Cox }
684806c35f5SAlan Cox
e752x_check_hub_interface(struct e752x_error_info * info,int * error_found,int handle_error)685806c35f5SAlan Cox static void e752x_check_hub_interface(struct e752x_error_info *info,
686806c35f5SAlan Cox int *error_found, int handle_error)
687806c35f5SAlan Cox {
688806c35f5SAlan Cox u8 stat8;
689806c35f5SAlan Cox
690806c35f5SAlan Cox //pci_read_config_byte(dev,E752X_HI_FERR,&stat8);
691e7ecd891SDave Peterson
692806c35f5SAlan Cox stat8 = info->hi_ferr;
693e7ecd891SDave Peterson
694806c35f5SAlan Cox if (stat8 & 0x7f) { /* Error, so process */
695806c35f5SAlan Cox stat8 &= 0x7f;
696e7ecd891SDave Peterson
697806c35f5SAlan Cox if (stat8 & 0x2b)
698806c35f5SAlan Cox hub_error(1, stat8 & 0x2b, error_found, handle_error);
699e7ecd891SDave Peterson
700806c35f5SAlan Cox if (stat8 & 0x54)
701806c35f5SAlan Cox hub_error(0, stat8 & 0x54, error_found, handle_error);
702806c35f5SAlan Cox }
703806c35f5SAlan Cox //pci_read_config_byte(dev,E752X_HI_NERR,&stat8);
704e7ecd891SDave Peterson
705806c35f5SAlan Cox stat8 = info->hi_nerr;
706e7ecd891SDave Peterson
707806c35f5SAlan Cox if (stat8 & 0x7f) { /* Error, so process */
708806c35f5SAlan Cox stat8 &= 0x7f;
709e7ecd891SDave Peterson
710806c35f5SAlan Cox if (stat8 & 0x2b)
711806c35f5SAlan Cox hub_error(1, stat8 & 0x2b, error_found, handle_error);
712e7ecd891SDave Peterson
713806c35f5SAlan Cox if (stat8 & 0x54)
714806c35f5SAlan Cox hub_error(0, stat8 & 0x54, error_found, handle_error);
715806c35f5SAlan Cox }
716806c35f5SAlan Cox }
717806c35f5SAlan Cox
e752x_check_ns_interface(struct e752x_error_info * info,int * error_found,int handle_error)7185135b797SAndrei Konovalov static void e752x_check_ns_interface(struct e752x_error_info *info,
7195135b797SAndrei Konovalov int *error_found, int handle_error)
7205135b797SAndrei Konovalov {
7215135b797SAndrei Konovalov u32 stat32;
7225135b797SAndrei Konovalov
7235135b797SAndrei Konovalov stat32 = info->nsi_ferr;
7245135b797SAndrei Konovalov if (stat32 & NSI_ERR_MASK) { /* Error, so process */
7255135b797SAndrei Konovalov if (stat32 & NSI_FATAL_MASK) /* check for fatal errors */
7265135b797SAndrei Konovalov nsi_error(1, stat32 & NSI_FATAL_MASK, error_found,
7275135b797SAndrei Konovalov handle_error);
7285135b797SAndrei Konovalov if (stat32 & NSI_NON_FATAL_MASK) /* check for non-fatal ones */
7295135b797SAndrei Konovalov nsi_error(0, stat32 & NSI_NON_FATAL_MASK, error_found,
7305135b797SAndrei Konovalov handle_error);
7315135b797SAndrei Konovalov }
7325135b797SAndrei Konovalov stat32 = info->nsi_nerr;
7335135b797SAndrei Konovalov if (stat32 & NSI_ERR_MASK) {
7345135b797SAndrei Konovalov if (stat32 & NSI_FATAL_MASK)
7355135b797SAndrei Konovalov nsi_error(1, stat32 & NSI_FATAL_MASK, error_found,
7365135b797SAndrei Konovalov handle_error);
7375135b797SAndrei Konovalov if (stat32 & NSI_NON_FATAL_MASK)
7385135b797SAndrei Konovalov nsi_error(0, stat32 & NSI_NON_FATAL_MASK, error_found,
7395135b797SAndrei Konovalov handle_error);
7405135b797SAndrei Konovalov }
7415135b797SAndrei Konovalov }
7425135b797SAndrei Konovalov
e752x_check_sysbus(struct e752x_error_info * info,int * error_found,int handle_error)743e7ecd891SDave Peterson static void e752x_check_sysbus(struct e752x_error_info *info,
744e7ecd891SDave Peterson int *error_found, int handle_error)
745806c35f5SAlan Cox {
746806c35f5SAlan Cox u32 stat32, error32;
747806c35f5SAlan Cox
748806c35f5SAlan Cox //pci_read_config_dword(dev,E752X_SYSBUS_FERR,&stat32);
749806c35f5SAlan Cox stat32 = info->sysbus_ferr + (info->sysbus_nerr << 16);
750806c35f5SAlan Cox
751806c35f5SAlan Cox if (stat32 == 0)
752806c35f5SAlan Cox return; /* no errors */
753806c35f5SAlan Cox
754806c35f5SAlan Cox error32 = (stat32 >> 16) & 0x3ff;
755806c35f5SAlan Cox stat32 = stat32 & 0x3ff;
756e7ecd891SDave Peterson
757dfb2a763SBrian Pomerantz if (stat32 & 0x087)
758dfb2a763SBrian Pomerantz sysbus_error(1, stat32 & 0x087, error_found, handle_error);
759e7ecd891SDave Peterson
760dfb2a763SBrian Pomerantz if (stat32 & 0x378)
761dfb2a763SBrian Pomerantz sysbus_error(0, stat32 & 0x378, error_found, handle_error);
762e7ecd891SDave Peterson
763dfb2a763SBrian Pomerantz if (error32 & 0x087)
764dfb2a763SBrian Pomerantz sysbus_error(1, error32 & 0x087, error_found, handle_error);
765e7ecd891SDave Peterson
766dfb2a763SBrian Pomerantz if (error32 & 0x378)
767dfb2a763SBrian Pomerantz sysbus_error(0, error32 & 0x378, error_found, handle_error);
768806c35f5SAlan Cox }
769806c35f5SAlan Cox
e752x_check_membuf(struct e752x_error_info * info,int * error_found,int handle_error)770e7ecd891SDave Peterson static void e752x_check_membuf(struct e752x_error_info *info,
771e7ecd891SDave Peterson int *error_found, int handle_error)
772806c35f5SAlan Cox {
773806c35f5SAlan Cox u8 stat8;
774806c35f5SAlan Cox
775806c35f5SAlan Cox stat8 = info->buf_ferr;
776e7ecd891SDave Peterson
777806c35f5SAlan Cox if (stat8 & 0x0f) { /* Error, so process */
778806c35f5SAlan Cox stat8 &= 0x0f;
779806c35f5SAlan Cox membuf_error(stat8, error_found, handle_error);
780806c35f5SAlan Cox }
781e7ecd891SDave Peterson
782806c35f5SAlan Cox stat8 = info->buf_nerr;
783e7ecd891SDave Peterson
784806c35f5SAlan Cox if (stat8 & 0x0f) { /* Error, so process */
785806c35f5SAlan Cox stat8 &= 0x0f;
786806c35f5SAlan Cox membuf_error(stat8, error_found, handle_error);
787806c35f5SAlan Cox }
788806c35f5SAlan Cox }
789806c35f5SAlan Cox
e752x_check_dram(struct mem_ctl_info * mci,struct e752x_error_info * info,int * error_found,int handle_error)790806c35f5SAlan Cox static void e752x_check_dram(struct mem_ctl_info *mci,
791e7ecd891SDave Peterson struct e752x_error_info *info, int *error_found,
792e7ecd891SDave Peterson int handle_error)
793806c35f5SAlan Cox {
794806c35f5SAlan Cox u16 error_one, error_next;
795806c35f5SAlan Cox
796806c35f5SAlan Cox error_one = info->dram_ferr;
797806c35f5SAlan Cox error_next = info->dram_nerr;
798806c35f5SAlan Cox
799806c35f5SAlan Cox /* decode and report errors */
800806c35f5SAlan Cox if (error_one & 0x0101) /* check first error correctable */
801806c35f5SAlan Cox process_ce(mci, error_one, info->dram_sec1_add,
802203333cbSDave Jiang info->dram_sec1_syndrome, error_found, handle_error);
803806c35f5SAlan Cox
804806c35f5SAlan Cox if (error_next & 0x0101) /* check next error correctable */
805806c35f5SAlan Cox process_ce(mci, error_next, info->dram_sec2_add,
806203333cbSDave Jiang info->dram_sec2_syndrome, error_found, handle_error);
807806c35f5SAlan Cox
808806c35f5SAlan Cox if (error_one & 0x4040)
809806c35f5SAlan Cox process_ue_no_info_wr(mci, error_found, handle_error);
810806c35f5SAlan Cox
811806c35f5SAlan Cox if (error_next & 0x4040)
812806c35f5SAlan Cox process_ue_no_info_wr(mci, error_found, handle_error);
813806c35f5SAlan Cox
814806c35f5SAlan Cox if (error_one & 0x2020)
815806c35f5SAlan Cox process_ded_retry(mci, error_one, info->dram_retr_add,
816806c35f5SAlan Cox error_found, handle_error);
817806c35f5SAlan Cox
818806c35f5SAlan Cox if (error_next & 0x2020)
819806c35f5SAlan Cox process_ded_retry(mci, error_next, info->dram_retr_add,
820806c35f5SAlan Cox error_found, handle_error);
821806c35f5SAlan Cox
822806c35f5SAlan Cox if (error_one & 0x0808)
823203333cbSDave Jiang process_threshold_ce(mci, error_one, error_found, handle_error);
824806c35f5SAlan Cox
825806c35f5SAlan Cox if (error_next & 0x0808)
826806c35f5SAlan Cox process_threshold_ce(mci, error_next, error_found,
827806c35f5SAlan Cox handle_error);
828806c35f5SAlan Cox
829806c35f5SAlan Cox if (error_one & 0x0606)
830806c35f5SAlan Cox process_ue(mci, error_one, info->dram_ded_add,
831806c35f5SAlan Cox info->dram_scrb_add, error_found, handle_error);
832806c35f5SAlan Cox
833806c35f5SAlan Cox if (error_next & 0x0606)
834806c35f5SAlan Cox process_ue(mci, error_next, info->dram_ded_add,
835806c35f5SAlan Cox info->dram_scrb_add, error_found, handle_error);
836806c35f5SAlan Cox }
837806c35f5SAlan Cox
e752x_get_error_info(struct mem_ctl_info * mci,struct e752x_error_info * info)838806c35f5SAlan Cox static void e752x_get_error_info(struct mem_ctl_info *mci,
839806c35f5SAlan Cox struct e752x_error_info *info)
840806c35f5SAlan Cox {
841806c35f5SAlan Cox struct pci_dev *dev;
842806c35f5SAlan Cox struct e752x_pvt *pvt;
843806c35f5SAlan Cox
844806c35f5SAlan Cox memset(info, 0, sizeof(*info));
845806c35f5SAlan Cox pvt = (struct e752x_pvt *)mci->pvt_info;
846806c35f5SAlan Cox dev = pvt->dev_d0f1;
847806c35f5SAlan Cox pci_read_config_dword(dev, E752X_FERR_GLOBAL, &info->ferr_global);
848806c35f5SAlan Cox
849806c35f5SAlan Cox if (info->ferr_global) {
8505135b797SAndrei Konovalov if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) {
8515135b797SAndrei Konovalov pci_read_config_dword(dev, I3100_NSI_FERR,
8525135b797SAndrei Konovalov &info->nsi_ferr);
8535135b797SAndrei Konovalov info->hi_ferr = 0;
8545135b797SAndrei Konovalov } else {
8555135b797SAndrei Konovalov pci_read_config_byte(dev, E752X_HI_FERR,
8565135b797SAndrei Konovalov &info->hi_ferr);
8575135b797SAndrei Konovalov info->nsi_ferr = 0;
8585135b797SAndrei Konovalov }
859806c35f5SAlan Cox pci_read_config_word(dev, E752X_SYSBUS_FERR,
860806c35f5SAlan Cox &info->sysbus_ferr);
861806c35f5SAlan Cox pci_read_config_byte(dev, E752X_BUF_FERR, &info->buf_ferr);
862203333cbSDave Jiang pci_read_config_word(dev, E752X_DRAM_FERR, &info->dram_ferr);
863806c35f5SAlan Cox pci_read_config_dword(dev, E752X_DRAM_SEC1_ADD,
864806c35f5SAlan Cox &info->dram_sec1_add);
865806c35f5SAlan Cox pci_read_config_word(dev, E752X_DRAM_SEC1_SYNDROME,
866806c35f5SAlan Cox &info->dram_sec1_syndrome);
867806c35f5SAlan Cox pci_read_config_dword(dev, E752X_DRAM_DED_ADD,
868806c35f5SAlan Cox &info->dram_ded_add);
869806c35f5SAlan Cox pci_read_config_dword(dev, E752X_DRAM_SCRB_ADD,
870806c35f5SAlan Cox &info->dram_scrb_add);
871806c35f5SAlan Cox pci_read_config_dword(dev, E752X_DRAM_RETR_ADD,
872806c35f5SAlan Cox &info->dram_retr_add);
873806c35f5SAlan Cox
8745135b797SAndrei Konovalov /* ignore the reserved bits just in case */
875806c35f5SAlan Cox if (info->hi_ferr & 0x7f)
876806c35f5SAlan Cox pci_write_config_byte(dev, E752X_HI_FERR,
877806c35f5SAlan Cox info->hi_ferr);
878806c35f5SAlan Cox
8795135b797SAndrei Konovalov if (info->nsi_ferr & NSI_ERR_MASK)
8805135b797SAndrei Konovalov pci_write_config_dword(dev, I3100_NSI_FERR,
8815135b797SAndrei Konovalov info->nsi_ferr);
8825135b797SAndrei Konovalov
883806c35f5SAlan Cox if (info->sysbus_ferr)
884806c35f5SAlan Cox pci_write_config_word(dev, E752X_SYSBUS_FERR,
885806c35f5SAlan Cox info->sysbus_ferr);
886806c35f5SAlan Cox
887806c35f5SAlan Cox if (info->buf_ferr & 0x0f)
888806c35f5SAlan Cox pci_write_config_byte(dev, E752X_BUF_FERR,
889806c35f5SAlan Cox info->buf_ferr);
890806c35f5SAlan Cox
891806c35f5SAlan Cox if (info->dram_ferr)
8920e089c18SJean Delvare pci_write_bits16(pvt->dev_d0f1, E752X_DRAM_FERR,
893806c35f5SAlan Cox info->dram_ferr, info->dram_ferr);
894806c35f5SAlan Cox
895806c35f5SAlan Cox pci_write_config_dword(dev, E752X_FERR_GLOBAL,
896806c35f5SAlan Cox info->ferr_global);
897806c35f5SAlan Cox }
898806c35f5SAlan Cox
899806c35f5SAlan Cox pci_read_config_dword(dev, E752X_NERR_GLOBAL, &info->nerr_global);
900806c35f5SAlan Cox
901806c35f5SAlan Cox if (info->nerr_global) {
9025135b797SAndrei Konovalov if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) {
9035135b797SAndrei Konovalov pci_read_config_dword(dev, I3100_NSI_NERR,
9045135b797SAndrei Konovalov &info->nsi_nerr);
9055135b797SAndrei Konovalov info->hi_nerr = 0;
9065135b797SAndrei Konovalov } else {
9075135b797SAndrei Konovalov pci_read_config_byte(dev, E752X_HI_NERR,
9085135b797SAndrei Konovalov &info->hi_nerr);
9095135b797SAndrei Konovalov info->nsi_nerr = 0;
9105135b797SAndrei Konovalov }
911806c35f5SAlan Cox pci_read_config_word(dev, E752X_SYSBUS_NERR,
912806c35f5SAlan Cox &info->sysbus_nerr);
913806c35f5SAlan Cox pci_read_config_byte(dev, E752X_BUF_NERR, &info->buf_nerr);
914203333cbSDave Jiang pci_read_config_word(dev, E752X_DRAM_NERR, &info->dram_nerr);
915806c35f5SAlan Cox pci_read_config_dword(dev, E752X_DRAM_SEC2_ADD,
916806c35f5SAlan Cox &info->dram_sec2_add);
917806c35f5SAlan Cox pci_read_config_word(dev, E752X_DRAM_SEC2_SYNDROME,
918806c35f5SAlan Cox &info->dram_sec2_syndrome);
919806c35f5SAlan Cox
920806c35f5SAlan Cox if (info->hi_nerr & 0x7f)
921806c35f5SAlan Cox pci_write_config_byte(dev, E752X_HI_NERR,
922806c35f5SAlan Cox info->hi_nerr);
923806c35f5SAlan Cox
9245135b797SAndrei Konovalov if (info->nsi_nerr & NSI_ERR_MASK)
9255135b797SAndrei Konovalov pci_write_config_dword(dev, I3100_NSI_NERR,
9265135b797SAndrei Konovalov info->nsi_nerr);
9275135b797SAndrei Konovalov
928806c35f5SAlan Cox if (info->sysbus_nerr)
929806c35f5SAlan Cox pci_write_config_word(dev, E752X_SYSBUS_NERR,
930806c35f5SAlan Cox info->sysbus_nerr);
931806c35f5SAlan Cox
932806c35f5SAlan Cox if (info->buf_nerr & 0x0f)
933806c35f5SAlan Cox pci_write_config_byte(dev, E752X_BUF_NERR,
934806c35f5SAlan Cox info->buf_nerr);
935806c35f5SAlan Cox
936806c35f5SAlan Cox if (info->dram_nerr)
9370e089c18SJean Delvare pci_write_bits16(pvt->dev_d0f1, E752X_DRAM_NERR,
938806c35f5SAlan Cox info->dram_nerr, info->dram_nerr);
939806c35f5SAlan Cox
940806c35f5SAlan Cox pci_write_config_dword(dev, E752X_NERR_GLOBAL,
941806c35f5SAlan Cox info->nerr_global);
942806c35f5SAlan Cox }
943806c35f5SAlan Cox }
944806c35f5SAlan Cox
e752x_process_error_info(struct mem_ctl_info * mci,struct e752x_error_info * info,int handle_errors)945806c35f5SAlan Cox static int e752x_process_error_info(struct mem_ctl_info *mci,
946203333cbSDave Jiang struct e752x_error_info *info,
947203333cbSDave Jiang int handle_errors)
948806c35f5SAlan Cox {
949806c35f5SAlan Cox u32 error32, stat32;
950806c35f5SAlan Cox int error_found;
951806c35f5SAlan Cox
952806c35f5SAlan Cox error_found = 0;
953806c35f5SAlan Cox error32 = (info->ferr_global >> 18) & 0x3ff;
954806c35f5SAlan Cox stat32 = (info->ferr_global >> 4) & 0x7ff;
955806c35f5SAlan Cox
956806c35f5SAlan Cox if (error32)
957806c35f5SAlan Cox global_error(1, error32, &error_found, handle_errors);
958806c35f5SAlan Cox
959806c35f5SAlan Cox if (stat32)
960806c35f5SAlan Cox global_error(0, stat32, &error_found, handle_errors);
961806c35f5SAlan Cox
962806c35f5SAlan Cox error32 = (info->nerr_global >> 18) & 0x3ff;
963806c35f5SAlan Cox stat32 = (info->nerr_global >> 4) & 0x7ff;
964806c35f5SAlan Cox
965806c35f5SAlan Cox if (error32)
966806c35f5SAlan Cox global_error(1, error32, &error_found, handle_errors);
967806c35f5SAlan Cox
968806c35f5SAlan Cox if (stat32)
969806c35f5SAlan Cox global_error(0, stat32, &error_found, handle_errors);
970806c35f5SAlan Cox
971806c35f5SAlan Cox e752x_check_hub_interface(info, &error_found, handle_errors);
9725135b797SAndrei Konovalov e752x_check_ns_interface(info, &error_found, handle_errors);
973806c35f5SAlan Cox e752x_check_sysbus(info, &error_found, handle_errors);
974806c35f5SAlan Cox e752x_check_membuf(info, &error_found, handle_errors);
975806c35f5SAlan Cox e752x_check_dram(mci, info, &error_found, handle_errors);
976806c35f5SAlan Cox return error_found;
977806c35f5SAlan Cox }
978806c35f5SAlan Cox
e752x_check(struct mem_ctl_info * mci)979806c35f5SAlan Cox static void e752x_check(struct mem_ctl_info *mci)
980806c35f5SAlan Cox {
981806c35f5SAlan Cox struct e752x_error_info info;
982e7ecd891SDave Peterson
983806c35f5SAlan Cox e752x_get_error_info(mci, &info);
984806c35f5SAlan Cox e752x_process_error_info(mci, &info, 1);
985806c35f5SAlan Cox }
986806c35f5SAlan Cox
9878004fd2aSPeter Tyser /* Program byte/sec bandwidth scrub rate to hardware */
set_sdram_scrub_rate(struct mem_ctl_info * mci,u32 new_bw)988eba042a8SBorislav Petkov static int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 new_bw)
9898004fd2aSPeter Tyser {
9908004fd2aSPeter Tyser const struct scrubrate *scrubrates;
9918004fd2aSPeter Tyser struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
9928004fd2aSPeter Tyser struct pci_dev *pdev = pvt->dev_d0f0;
9938004fd2aSPeter Tyser int i;
9948004fd2aSPeter Tyser
9958004fd2aSPeter Tyser if (pvt->dev_info->ctl_dev == PCI_DEVICE_ID_INTEL_3100_0)
9968004fd2aSPeter Tyser scrubrates = scrubrates_i3100;
9978004fd2aSPeter Tyser else
9988004fd2aSPeter Tyser scrubrates = scrubrates_e752x;
9998004fd2aSPeter Tyser
10008004fd2aSPeter Tyser /* Translate the desired scrub rate to a e752x/3100 register value.
10018004fd2aSPeter Tyser * Search for the bandwidth that is equal or greater than the
10028004fd2aSPeter Tyser * desired rate and program the cooresponding register value.
10038004fd2aSPeter Tyser */
10048004fd2aSPeter Tyser for (i = 0; scrubrates[i].bandwidth != SDRATE_EOT; i++)
1005eba042a8SBorislav Petkov if (scrubrates[i].bandwidth >= new_bw)
10068004fd2aSPeter Tyser break;
10078004fd2aSPeter Tyser
10088004fd2aSPeter Tyser if (scrubrates[i].bandwidth == SDRATE_EOT)
10098004fd2aSPeter Tyser return -1;
10108004fd2aSPeter Tyser
10118004fd2aSPeter Tyser pci_write_config_word(pdev, E752X_MCHSCRB, scrubrates[i].scrubval);
10128004fd2aSPeter Tyser
101339094443SBorislav Petkov return scrubrates[i].bandwidth;
10148004fd2aSPeter Tyser }
10158004fd2aSPeter Tyser
10168004fd2aSPeter Tyser /* Convert current scrub rate value into byte/sec bandwidth */
get_sdram_scrub_rate(struct mem_ctl_info * mci)101739094443SBorislav Petkov static int get_sdram_scrub_rate(struct mem_ctl_info *mci)
10188004fd2aSPeter Tyser {
10198004fd2aSPeter Tyser const struct scrubrate *scrubrates;
10208004fd2aSPeter Tyser struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
10218004fd2aSPeter Tyser struct pci_dev *pdev = pvt->dev_d0f0;
10228004fd2aSPeter Tyser u16 scrubval;
10238004fd2aSPeter Tyser int i;
10248004fd2aSPeter Tyser
10258004fd2aSPeter Tyser if (pvt->dev_info->ctl_dev == PCI_DEVICE_ID_INTEL_3100_0)
10268004fd2aSPeter Tyser scrubrates = scrubrates_i3100;
10278004fd2aSPeter Tyser else
10288004fd2aSPeter Tyser scrubrates = scrubrates_e752x;
10298004fd2aSPeter Tyser
10308004fd2aSPeter Tyser /* Find the bandwidth matching the memory scrubber configuration */
10318004fd2aSPeter Tyser pci_read_config_word(pdev, E752X_MCHSCRB, &scrubval);
10328004fd2aSPeter Tyser scrubval = scrubval & 0x0f;
10338004fd2aSPeter Tyser
10348004fd2aSPeter Tyser for (i = 0; scrubrates[i].bandwidth != SDRATE_EOT; i++)
10358004fd2aSPeter Tyser if (scrubrates[i].scrubval == scrubval)
10368004fd2aSPeter Tyser break;
10378004fd2aSPeter Tyser
10388004fd2aSPeter Tyser if (scrubrates[i].bandwidth == SDRATE_EOT) {
10398004fd2aSPeter Tyser e752x_printk(KERN_WARNING,
10408004fd2aSPeter Tyser "Invalid sdram scrub control value: 0x%x\n", scrubval);
10418004fd2aSPeter Tyser return -1;
10428004fd2aSPeter Tyser }
104339094443SBorislav Petkov return scrubrates[i].bandwidth;
10448004fd2aSPeter Tyser
10458004fd2aSPeter Tyser }
10468004fd2aSPeter Tyser
104713189525SDoug Thompson /* Return 1 if dual channel mode is active. Else return 0. */
dual_channel_active(u16 ddrcsr)104813189525SDoug Thompson static inline int dual_channel_active(u16 ddrcsr)
1049806c35f5SAlan Cox {
105013189525SDoug Thompson return (((ddrcsr >> 12) & 3) == 3);
105113189525SDoug Thompson }
105213189525SDoug Thompson
10537297c261SMark Grondona /* Remap csrow index numbers if map_type is "reverse"
10547297c261SMark Grondona */
remap_csrow_index(struct mem_ctl_info * mci,int index)10557297c261SMark Grondona static inline int remap_csrow_index(struct mem_ctl_info *mci, int index)
10567297c261SMark Grondona {
10577297c261SMark Grondona struct e752x_pvt *pvt = mci->pvt_info;
10587297c261SMark Grondona
10597297c261SMark Grondona if (!pvt->map_type)
10607297c261SMark Grondona return (7 - index);
10617297c261SMark Grondona
10627297c261SMark Grondona return (index);
10637297c261SMark Grondona }
10647297c261SMark Grondona
e752x_init_csrows(struct mem_ctl_info * mci,struct pci_dev * pdev,u16 ddrcsr)106513189525SDoug Thompson static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
106613189525SDoug Thompson u16 ddrcsr)
106713189525SDoug Thompson {
106813189525SDoug Thompson struct csrow_info *csrow;
1069fd63312dSMauro Carvalho Chehab enum edac_type edac_mode;
107013189525SDoug Thompson unsigned long last_cumul_size;
107113189525SDoug Thompson int index, mem_dev, drc_chan;
1072806c35f5SAlan Cox int drc_drbg; /* DRB granularity 0=64mb, 1=128mb */
1073806c35f5SAlan Cox int drc_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */
107413189525SDoug Thompson u8 value;
1075a895bf8bSMauro Carvalho Chehab u32 dra, drc, cumul_size, i, nr_pages;
1076806c35f5SAlan Cox
10779962fd01SBrian Pomerantz dra = 0;
10789962fd01SBrian Pomerantz for (index = 0; index < 4; index++) {
10799962fd01SBrian Pomerantz u8 dra_reg;
10809962fd01SBrian Pomerantz pci_read_config_byte(pdev, E752X_DRA + index, &dra_reg);
10819962fd01SBrian Pomerantz dra |= dra_reg << (index * 8);
10829962fd01SBrian Pomerantz }
1083806c35f5SAlan Cox pci_read_config_dword(pdev, E752X_DRC, &drc);
1084084a4fccSMauro Carvalho Chehab drc_chan = dual_channel_active(ddrcsr) ? 1 : 0;
1085806c35f5SAlan Cox drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */
1086806c35f5SAlan Cox drc_ddim = (drc >> 20) & 0x3;
1087806c35f5SAlan Cox
108813189525SDoug Thompson /* The dram row boundary (DRB) reg values are boundary address for
1089806c35f5SAlan Cox * each DRAM row with a granularity of 64 or 128MB (single/dual
1090806c35f5SAlan Cox * channel operation). DRB regs are cumulative; therefore DRB7 will
1091806c35f5SAlan Cox * contain the total memory contained in all eight rows.
1092806c35f5SAlan Cox */
1093806c35f5SAlan Cox for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) {
1094806c35f5SAlan Cox /* mem_dev 0=x8, 1=x4 */
109513189525SDoug Thompson mem_dev = (dra >> (index * 4 + 2)) & 0x3;
1096de3910ebSMauro Carvalho Chehab csrow = mci->csrows[remap_csrow_index(mci, index)];
1097806c35f5SAlan Cox
1098806c35f5SAlan Cox mem_dev = (mem_dev == 2);
109937f04581SDoug Thompson pci_read_config_byte(pdev, E752X_DRB + index, &value);
1100806c35f5SAlan Cox /* convert a 128 or 64 MiB DRB to a page size. */
1101806c35f5SAlan Cox cumul_size = value << (25 + drc_drbg - PAGE_SHIFT);
1102956b9ba1SJoe Perches edac_dbg(3, "(%d) cumul_size 0x%x\n", index, cumul_size);
1103806c35f5SAlan Cox if (cumul_size == last_cumul_size)
1104806c35f5SAlan Cox continue; /* not populated */
1105806c35f5SAlan Cox
1106806c35f5SAlan Cox csrow->first_page = last_cumul_size;
1107806c35f5SAlan Cox csrow->last_page = cumul_size - 1;
1108a895bf8bSMauro Carvalho Chehab nr_pages = cumul_size - last_cumul_size;
1109806c35f5SAlan Cox last_cumul_size = cumul_size;
1110084a4fccSMauro Carvalho Chehab
1111fd63312dSMauro Carvalho Chehab /*
1112fd63312dSMauro Carvalho Chehab * if single channel or x8 devices then SECDED
1113fd63312dSMauro Carvalho Chehab * if dual channel and x4 then S4ECD4ED
1114fd63312dSMauro Carvalho Chehab */
1115fd63312dSMauro Carvalho Chehab if (drc_ddim) {
1116fd63312dSMauro Carvalho Chehab if (drc_chan && mem_dev) {
1117fd63312dSMauro Carvalho Chehab edac_mode = EDAC_S4ECD4ED;
1118fd63312dSMauro Carvalho Chehab mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
1119fd63312dSMauro Carvalho Chehab } else {
1120fd63312dSMauro Carvalho Chehab edac_mode = EDAC_SECDED;
1121fd63312dSMauro Carvalho Chehab mci->edac_cap |= EDAC_FLAG_SECDED;
1122fd63312dSMauro Carvalho Chehab }
1123fd63312dSMauro Carvalho Chehab } else
1124fd63312dSMauro Carvalho Chehab edac_mode = EDAC_NONE;
1125ce11ce17SMauro Carvalho Chehab for (i = 0; i < csrow->nr_channels; i++) {
1126de3910ebSMauro Carvalho Chehab struct dimm_info *dimm = csrow->channels[i]->dimm;
1127a895bf8bSMauro Carvalho Chehab
1128956b9ba1SJoe Perches edac_dbg(3, "Initializing rank at (%i,%i)\n", index, i);
1129ce11ce17SMauro Carvalho Chehab dimm->nr_pages = nr_pages / csrow->nr_channels;
1130084a4fccSMauro Carvalho Chehab dimm->grain = 1 << 12; /* 4KiB - resolution of CELOG */
1131084a4fccSMauro Carvalho Chehab dimm->mtype = MEM_RDDR; /* only one type supported */
1132084a4fccSMauro Carvalho Chehab dimm->dtype = mem_dev ? DEV_X4 : DEV_X8;
1133fd63312dSMauro Carvalho Chehab dimm->edac_mode = edac_mode;
1134084a4fccSMauro Carvalho Chehab }
1135806c35f5SAlan Cox }
113613189525SDoug Thompson }
1137806c35f5SAlan Cox
e752x_init_mem_map_table(struct pci_dev * pdev,struct e752x_pvt * pvt)113813189525SDoug Thompson static void e752x_init_mem_map_table(struct pci_dev *pdev,
113913189525SDoug Thompson struct e752x_pvt *pvt)
1140806c35f5SAlan Cox {
114113189525SDoug Thompson int index;
11427297c261SMark Grondona u8 value, last, row;
114313189525SDoug Thompson
114413189525SDoug Thompson last = 0;
114513189525SDoug Thompson row = 0;
1146806c35f5SAlan Cox
1147e7ecd891SDave Peterson for (index = 0; index < 8; index += 2) {
114837f04581SDoug Thompson pci_read_config_byte(pdev, E752X_DRB + index, &value);
1149806c35f5SAlan Cox /* test if there is a dimm in this slot */
1150806c35f5SAlan Cox if (value == last) {
1151806c35f5SAlan Cox /* no dimm in the slot, so flag it as empty */
1152806c35f5SAlan Cox pvt->map[index] = 0xff;
1153806c35f5SAlan Cox pvt->map[index + 1] = 0xff;
1154806c35f5SAlan Cox } else { /* there is a dimm in the slot */
1155806c35f5SAlan Cox pvt->map[index] = row;
1156806c35f5SAlan Cox row++;
1157806c35f5SAlan Cox last = value;
115813189525SDoug Thompson /* test the next value to see if the dimm is double
115913189525SDoug Thompson * sided
116013189525SDoug Thompson */
116113189525SDoug Thompson pci_read_config_byte(pdev, E752X_DRB + index + 1,
1162806c35f5SAlan Cox &value);
1163052dfb45SDouglas Thompson
1164052dfb45SDouglas Thompson /* the dimm is single sided, so flag as empty */
1165052dfb45SDouglas Thompson /* this is a double sided dimm to save the next row #*/
1166052dfb45SDouglas Thompson pvt->map[index + 1] = (value == last) ? 0xff : row;
1167806c35f5SAlan Cox row++;
1168806c35f5SAlan Cox last = value;
1169806c35f5SAlan Cox }
1170806c35f5SAlan Cox }
1171806c35f5SAlan Cox }
1172806c35f5SAlan Cox
117313189525SDoug Thompson /* Return 0 on success or 1 on failure. */
e752x_get_devs(struct pci_dev * pdev,int dev_idx,struct e752x_pvt * pvt)117413189525SDoug Thompson static int e752x_get_devs(struct pci_dev *pdev, int dev_idx,
117513189525SDoug Thompson struct e752x_pvt *pvt)
117613189525SDoug Thompson {
11770e089c18SJean Delvare pvt->dev_d0f1 = pci_get_device(PCI_VENDOR_ID_INTEL,
11782edbf569SJean Delvare pvt->dev_info->err_dev, NULL);
117913189525SDoug Thompson
11800e089c18SJean Delvare if (pvt->dev_d0f1 == NULL) {
11810e089c18SJean Delvare pvt->dev_d0f1 = pci_scan_single_device(pdev->bus,
118213189525SDoug Thompson PCI_DEVFN(0, 1));
11830e089c18SJean Delvare pci_dev_get(pvt->dev_d0f1);
118490ed4988SAristeu Rozanski }
118513189525SDoug Thompson
11860e089c18SJean Delvare if (pvt->dev_d0f1 == NULL) {
118713189525SDoug Thompson e752x_printk(KERN_ERR, "error reporting device not found:"
118813189525SDoug Thompson "vendor %x device 0x%x (broken BIOS?)\n",
118913189525SDoug Thompson PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev);
119013189525SDoug Thompson return 1;
119113189525SDoug Thompson }
119213189525SDoug Thompson
11930e089c18SJean Delvare pvt->dev_d0f0 = pci_get_device(PCI_VENDOR_ID_INTEL,
119410d33e9cSDoug Thompson e752x_devs[dev_idx].ctl_dev,
119513189525SDoug Thompson NULL);
119613189525SDoug Thompson
11970e089c18SJean Delvare if (pvt->dev_d0f0 == NULL)
119813189525SDoug Thompson goto fail;
119913189525SDoug Thompson
120013189525SDoug Thompson return 0;
120113189525SDoug Thompson
120213189525SDoug Thompson fail:
12030e089c18SJean Delvare pci_dev_put(pvt->dev_d0f1);
120413189525SDoug Thompson return 1;
120513189525SDoug Thompson }
120613189525SDoug Thompson
120794ee1cf5SPeter Tyser /* Setup system bus parity mask register.
120894ee1cf5SPeter Tyser * Sysbus parity supported on:
120994ee1cf5SPeter Tyser * e7320/e7520/e7525 + Xeon
121094ee1cf5SPeter Tyser */
e752x_init_sysbus_parity_mask(struct e752x_pvt * pvt)121194ee1cf5SPeter Tyser static void e752x_init_sysbus_parity_mask(struct e752x_pvt *pvt)
121294ee1cf5SPeter Tyser {
121394ee1cf5SPeter Tyser char *cpu_id = cpu_data(0).x86_model_id;
121494ee1cf5SPeter Tyser struct pci_dev *dev = pvt->dev_d0f1;
121594ee1cf5SPeter Tyser int enable = 1;
121694ee1cf5SPeter Tyser
121798a1708dSMartin Olsson /* Allow module parameter override, else see if CPU supports parity */
121894ee1cf5SPeter Tyser if (sysbus_parity != -1) {
121994ee1cf5SPeter Tyser enable = sysbus_parity;
12208de5c1a1SKonstantin Olifer } else if (cpu_id[0] && !strstr(cpu_id, "Xeon")) {
122194ee1cf5SPeter Tyser e752x_printk(KERN_INFO, "System Bus Parity not "
122294ee1cf5SPeter Tyser "supported by CPU, disabling\n");
122394ee1cf5SPeter Tyser enable = 0;
122494ee1cf5SPeter Tyser }
122594ee1cf5SPeter Tyser
122694ee1cf5SPeter Tyser if (enable)
122794ee1cf5SPeter Tyser pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x0000);
122894ee1cf5SPeter Tyser else
122994ee1cf5SPeter Tyser pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x0309);
123094ee1cf5SPeter Tyser }
123194ee1cf5SPeter Tyser
e752x_init_error_reporting_regs(struct e752x_pvt * pvt)123213189525SDoug Thompson static void e752x_init_error_reporting_regs(struct e752x_pvt *pvt)
123313189525SDoug Thompson {
123413189525SDoug Thompson struct pci_dev *dev;
123513189525SDoug Thompson
123613189525SDoug Thompson dev = pvt->dev_d0f1;
123713189525SDoug Thompson /* Turn off error disable & SMI in case the BIOS turned it on */
12385135b797SAndrei Konovalov if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) {
12395135b797SAndrei Konovalov pci_write_config_dword(dev, I3100_NSI_EMASK, 0);
12405135b797SAndrei Konovalov pci_write_config_dword(dev, I3100_NSI_SMICMD, 0);
12415135b797SAndrei Konovalov } else {
124213189525SDoug Thompson pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00);
124313189525SDoug Thompson pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00);
12445135b797SAndrei Konovalov }
124594ee1cf5SPeter Tyser
124694ee1cf5SPeter Tyser e752x_init_sysbus_parity_mask(pvt);
124794ee1cf5SPeter Tyser
124813189525SDoug Thompson pci_write_config_word(dev, E752X_SYSBUS_SMICMD, 0x00);
124913189525SDoug Thompson pci_write_config_byte(dev, E752X_BUF_ERRMASK, 0x00);
125013189525SDoug Thompson pci_write_config_byte(dev, E752X_BUF_SMICMD, 0x00);
125113189525SDoug Thompson pci_write_config_byte(dev, E752X_DRAM_ERRMASK, 0x00);
125213189525SDoug Thompson pci_write_config_byte(dev, E752X_DRAM_SMICMD, 0x00);
125313189525SDoug Thompson }
125413189525SDoug Thompson
e752x_probe1(struct pci_dev * pdev,int dev_idx)125513189525SDoug Thompson static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
125613189525SDoug Thompson {
125713189525SDoug Thompson u16 pci_data;
125813189525SDoug Thompson u8 stat8;
125913189525SDoug Thompson struct mem_ctl_info *mci;
1260ce11ce17SMauro Carvalho Chehab struct edac_mc_layer layers[2];
126113189525SDoug Thompson struct e752x_pvt *pvt;
126213189525SDoug Thompson u16 ddrcsr;
126313189525SDoug Thompson int drc_chan; /* Number of channels 0=1chan,1=2chan */
126413189525SDoug Thompson struct e752x_error_info discard;
126513189525SDoug Thompson
1266956b9ba1SJoe Perches edac_dbg(0, "mci\n");
1267956b9ba1SJoe Perches edac_dbg(0, "Starting Probe1\n");
126813189525SDoug Thompson
126913189525SDoug Thompson /* check to see if device 0 function 1 is enabled; if it isn't, we
127013189525SDoug Thompson * assume the BIOS has reserved it for a reason and is expecting
127113189525SDoug Thompson * exclusive access, we take care not to violate that assumption and
127213189525SDoug Thompson * fail the probe. */
127313189525SDoug Thompson pci_read_config_byte(pdev, E752X_DEVPRES1, &stat8);
127413189525SDoug Thompson if (!force_function_unhide && !(stat8 & (1 << 5))) {
127513189525SDoug Thompson printk(KERN_INFO "Contact your BIOS vendor to see if the "
127613189525SDoug Thompson "E752x error registers can be safely un-hidden\n");
1277f9b5a5d1SAristeu Rozanski return -ENODEV;
127813189525SDoug Thompson }
127913189525SDoug Thompson stat8 |= (1 << 5);
128013189525SDoug Thompson pci_write_config_byte(pdev, E752X_DEVPRES1, stat8);
128113189525SDoug Thompson
128213189525SDoug Thompson pci_read_config_word(pdev, E752X_DDRCSR, &ddrcsr);
128313189525SDoug Thompson /* FIXME: should check >>12 or 0xf, true for all? */
128413189525SDoug Thompson /* Dual channel = 1, Single channel = 0 */
128513189525SDoug Thompson drc_chan = dual_channel_active(ddrcsr);
128613189525SDoug Thompson
1287ce11ce17SMauro Carvalho Chehab layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
1288ce11ce17SMauro Carvalho Chehab layers[0].size = E752X_NR_CSROWS;
1289ce11ce17SMauro Carvalho Chehab layers[0].is_virt_csrow = true;
1290ce11ce17SMauro Carvalho Chehab layers[1].type = EDAC_MC_LAYER_CHANNEL;
1291ce11ce17SMauro Carvalho Chehab layers[1].size = drc_chan + 1;
1292ce11ce17SMauro Carvalho Chehab layers[1].is_virt_csrow = false;
1293ca0907b9SMauro Carvalho Chehab mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt));
1294ce11ce17SMauro Carvalho Chehab if (mci == NULL)
129513189525SDoug Thompson return -ENOMEM;
129613189525SDoug Thompson
1297956b9ba1SJoe Perches edac_dbg(3, "init mci\n");
129813189525SDoug Thompson mci->mtype_cap = MEM_FLAG_RDDR;
12995135b797SAndrei Konovalov /* 3100 IMCH supports SECDEC only */
13005135b797SAndrei Konovalov mci->edac_ctl_cap = (dev_idx == I3100) ? EDAC_FLAG_SECDED :
13015135b797SAndrei Konovalov (EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_S4ECD4ED);
130213189525SDoug Thompson /* FIXME - what if different memory types are in different csrows? */
130313189525SDoug Thompson mci->mod_name = EDAC_MOD_STR;
1304fd687502SMauro Carvalho Chehab mci->pdev = &pdev->dev;
130513189525SDoug Thompson
1306956b9ba1SJoe Perches edac_dbg(3, "init pvt\n");
130713189525SDoug Thompson pvt = (struct e752x_pvt *)mci->pvt_info;
130813189525SDoug Thompson pvt->dev_info = &e752x_devs[dev_idx];
130913189525SDoug Thompson pvt->mc_symmetric = ((ddrcsr & 0x10) != 0);
131013189525SDoug Thompson
131113189525SDoug Thompson if (e752x_get_devs(pdev, dev_idx, pvt)) {
131213189525SDoug Thompson edac_mc_free(mci);
131313189525SDoug Thompson return -ENODEV;
131413189525SDoug Thompson }
131513189525SDoug Thompson
1316956b9ba1SJoe Perches edac_dbg(3, "more mci init\n");
131713189525SDoug Thompson mci->ctl_name = pvt->dev_info->ctl_name;
1318c4192705SDave Jiang mci->dev_name = pci_name(pdev);
131913189525SDoug Thompson mci->edac_check = e752x_check;
132013189525SDoug Thompson mci->ctl_page_to_phys = ctl_page_to_phys;
13218004fd2aSPeter Tyser mci->set_sdram_scrub_rate = set_sdram_scrub_rate;
13228004fd2aSPeter Tyser mci->get_sdram_scrub_rate = get_sdram_scrub_rate;
132313189525SDoug Thompson
13247297c261SMark Grondona /* set the map type. 1 = normal, 0 = reversed
13257297c261SMark Grondona * Must be set before e752x_init_csrows in case csrow mapping
13267297c261SMark Grondona * is reversed.
13277297c261SMark Grondona */
132837f04581SDoug Thompson pci_read_config_byte(pdev, E752X_DRM, &stat8);
1329806c35f5SAlan Cox pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f));
1330806c35f5SAlan Cox
13317297c261SMark Grondona e752x_init_csrows(mci, pdev, ddrcsr);
13327297c261SMark Grondona e752x_init_mem_map_table(pdev, pvt);
13337297c261SMark Grondona
13345135b797SAndrei Konovalov if (dev_idx == I3100)
13355135b797SAndrei Konovalov mci->edac_cap = EDAC_FLAG_SECDED; /* the only mode supported */
13365135b797SAndrei Konovalov else
1337806c35f5SAlan Cox mci->edac_cap |= EDAC_FLAG_NONE;
1338956b9ba1SJoe Perches edac_dbg(3, "tolm, remapbase, remaplimit\n");
1339e7ecd891SDave Peterson
1340806c35f5SAlan Cox /* load the top of low memory, remap base, and remap limit vars */
134137f04581SDoug Thompson pci_read_config_word(pdev, E752X_TOLM, &pci_data);
1342806c35f5SAlan Cox pvt->tolm = ((u32) pci_data) << 4;
134337f04581SDoug Thompson pci_read_config_word(pdev, E752X_REMAPBASE, &pci_data);
1344806c35f5SAlan Cox pvt->remapbase = ((u32) pci_data) << 14;
134537f04581SDoug Thompson pci_read_config_word(pdev, E752X_REMAPLIMIT, &pci_data);
1346806c35f5SAlan Cox pvt->remaplimit = ((u32) pci_data) << 14;
1347537fba28SDave Peterson e752x_printk(KERN_INFO,
1348052dfb45SDouglas Thompson "tolm = %x, remapbase = %x, remaplimit = %x\n",
1349052dfb45SDouglas Thompson pvt->tolm, pvt->remapbase, pvt->remaplimit);
1350806c35f5SAlan Cox
13512d7bbb91SDoug Thompson /* Here we assume that we will never see multiple instances of this
13522d7bbb91SDoug Thompson * type of memory controller. The ID is therefore hardcoded to 0.
13532d7bbb91SDoug Thompson */
1354b8f6f975SDoug Thompson if (edac_mc_add_mc(mci)) {
1355956b9ba1SJoe Perches edac_dbg(3, "failed edac_mc_add_mc()\n");
1356806c35f5SAlan Cox goto fail;
1357806c35f5SAlan Cox }
1358806c35f5SAlan Cox
135913189525SDoug Thompson e752x_init_error_reporting_regs(pvt);
1360e7ecd891SDave Peterson e752x_get_error_info(mci, &discard); /* clear other MCH errors */
1361806c35f5SAlan Cox
136291b99041SDave Jiang /* allocating generic PCI control info */
136391b99041SDave Jiang e752x_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
136491b99041SDave Jiang if (!e752x_pci) {
136591b99041SDave Jiang printk(KERN_WARNING
1366203333cbSDave Jiang "%s(): Unable to create PCI control\n", __func__);
136791b99041SDave Jiang printk(KERN_WARNING
1368052dfb45SDouglas Thompson "%s(): PCI error report via EDAC not setup\n",
1369052dfb45SDouglas Thompson __func__);
137091b99041SDave Jiang }
137191b99041SDave Jiang
1372806c35f5SAlan Cox /* get this far and it's successful */
1373956b9ba1SJoe Perches edac_dbg(3, "success\n");
1374806c35f5SAlan Cox return 0;
1375806c35f5SAlan Cox
1376806c35f5SAlan Cox fail:
1377806c35f5SAlan Cox pci_dev_put(pvt->dev_d0f0);
1378806c35f5SAlan Cox pci_dev_put(pvt->dev_d0f1);
1379806c35f5SAlan Cox edac_mc_free(mci);
1380e7ecd891SDave Peterson
138113189525SDoug Thompson return -ENODEV;
1382806c35f5SAlan Cox }
1383806c35f5SAlan Cox
1384806c35f5SAlan Cox /* returns count (>= 0), or negative on error */
e752x_init_one(struct pci_dev * pdev,const struct pci_device_id * ent)13859b3c6e85SGreg Kroah-Hartman static int e752x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
1386806c35f5SAlan Cox {
1387956b9ba1SJoe Perches edac_dbg(0, "\n");
1388806c35f5SAlan Cox
1389806c35f5SAlan Cox /* wake up and enable device */
1390806c35f5SAlan Cox if (pci_enable_device(pdev) < 0)
1391806c35f5SAlan Cox return -EIO;
1392e7ecd891SDave Peterson
1393806c35f5SAlan Cox return e752x_probe1(pdev, ent->driver_data);
1394806c35f5SAlan Cox }
1395806c35f5SAlan Cox
e752x_remove_one(struct pci_dev * pdev)13969b3c6e85SGreg Kroah-Hartman static void e752x_remove_one(struct pci_dev *pdev)
1397806c35f5SAlan Cox {
1398806c35f5SAlan Cox struct mem_ctl_info *mci;
1399806c35f5SAlan Cox struct e752x_pvt *pvt;
1400806c35f5SAlan Cox
1401956b9ba1SJoe Perches edac_dbg(0, "\n");
1402806c35f5SAlan Cox
140391b99041SDave Jiang if (e752x_pci)
140491b99041SDave Jiang edac_pci_release_generic_ctl(e752x_pci);
140591b99041SDave Jiang
140637f04581SDoug Thompson if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
1407806c35f5SAlan Cox return;
1408806c35f5SAlan Cox
1409806c35f5SAlan Cox pvt = (struct e752x_pvt *)mci->pvt_info;
1410806c35f5SAlan Cox pci_dev_put(pvt->dev_d0f0);
1411806c35f5SAlan Cox pci_dev_put(pvt->dev_d0f1);
1412806c35f5SAlan Cox edac_mc_free(mci);
1413806c35f5SAlan Cox }
1414806c35f5SAlan Cox
1415ba935f40SJingoo Han static const struct pci_device_id e752x_pci_tbl[] = {
1416e7ecd891SDave Peterson {
1417e7ecd891SDave Peterson PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
1418203333cbSDave Jiang E7520},
1419e7ecd891SDave Peterson {
1420e7ecd891SDave Peterson PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
1421203333cbSDave Jiang E7525},
1422e7ecd891SDave Peterson {
1423e7ecd891SDave Peterson PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
1424203333cbSDave Jiang E7320},
1425e7ecd891SDave Peterson {
14265135b797SAndrei Konovalov PCI_VEND_DEV(INTEL, 3100_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
14275135b797SAndrei Konovalov I3100},
14285135b797SAndrei Konovalov {
1429e7ecd891SDave Peterson 0,
1430e7ecd891SDave Peterson } /* 0 terminated list. */
1431806c35f5SAlan Cox };
1432806c35f5SAlan Cox
1433806c35f5SAlan Cox MODULE_DEVICE_TABLE(pci, e752x_pci_tbl);
1434806c35f5SAlan Cox
1435806c35f5SAlan Cox static struct pci_driver e752x_driver = {
1436680cbbbbSDave Peterson .name = EDAC_MOD_STR,
14370d38b049SRandy Dunlap .probe = e752x_init_one,
14389b3c6e85SGreg Kroah-Hartman .remove = e752x_remove_one,
14390d38b049SRandy Dunlap .id_table = e752x_pci_tbl,
1440806c35f5SAlan Cox };
1441806c35f5SAlan Cox
e752x_init(void)1442da9bb1d2SAlan Cox static int __init e752x_init(void)
1443806c35f5SAlan Cox {
1444806c35f5SAlan Cox int pci_rc;
1445806c35f5SAlan Cox
1446956b9ba1SJoe Perches edac_dbg(3, "\n");
1447c3c52bceSHitoshi Mitake
1448c3c52bceSHitoshi Mitake /* Ensure that the OPSTATE is set correctly for POLL or NMI */
1449c3c52bceSHitoshi Mitake opstate_init();
1450c3c52bceSHitoshi Mitake
1451806c35f5SAlan Cox pci_rc = pci_register_driver(&e752x_driver);
1452806c35f5SAlan Cox return (pci_rc < 0) ? pci_rc : 0;
1453806c35f5SAlan Cox }
1454806c35f5SAlan Cox
e752x_exit(void)1455806c35f5SAlan Cox static void __exit e752x_exit(void)
1456806c35f5SAlan Cox {
1457956b9ba1SJoe Perches edac_dbg(3, "\n");
1458806c35f5SAlan Cox pci_unregister_driver(&e752x_driver);
1459806c35f5SAlan Cox }
1460806c35f5SAlan Cox
1461806c35f5SAlan Cox module_init(e752x_init);
1462806c35f5SAlan Cox module_exit(e752x_exit);
1463806c35f5SAlan Cox
1464806c35f5SAlan Cox MODULE_LICENSE("GPL");
1465*371b27f2SBorislav Petkov (AMD) MODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman");
14665135b797SAndrei Konovalov MODULE_DESCRIPTION("MC support for Intel e752x/3100 memory controllers");
146796941026Smark gross
146896941026Smark gross module_param(force_function_unhide, int, 0444);
146996941026Smark gross MODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:"
147010d33e9cSDoug Thompson " 1=force unhide and hope BIOS doesn't fight driver for "
147110d33e9cSDoug Thompson "Dev0:Fun1 access");
1472c3c52bceSHitoshi Mitake
1473c0d12172SDave Jiang module_param(edac_op_state, int, 0444);
1474c0d12172SDave Jiang MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
147594ee1cf5SPeter Tyser
147694ee1cf5SPeter Tyser module_param(sysbus_parity, int, 0444);
147794ee1cf5SPeter Tyser MODULE_PARM_DESC(sysbus_parity, "0=disable system bus parity checking,"
147894ee1cf5SPeter Tyser " 1=enable system bus parity checking, default=auto-detect");
147910d33e9cSDoug Thompson module_param(report_non_memory_errors, int, 0644);
148010d33e9cSDoug Thompson MODULE_PARM_DESC(report_non_memory_errors, "0=disable non-memory error "
148110d33e9cSDoug Thompson "reporting, 1=enable non-memory error reporting");
1482