aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac
diff options
context:
space:
mode:
authorAlan Cox <alan@lxorguk.ukuu.org.uk>2006-01-18 20:44:10 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-18 22:20:31 -0500
commit0d88a10e566d46bffc214c974e5cf5abe38d8da8 (patch)
tree63a6c0ad4fbd33c192c2ed62808f0220364ba07e /drivers/edac
parent806c35f5057a64d3061ee4e2b1023bf6f6d328e2 (diff)
[PATCH] EDAC: drivers for Intel i82860, i82875
Signed-off-by: Alan Cox <alan@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/edac')
-rw-r--r--drivers/edac/i82860_edac.c299
-rw-r--r--drivers/edac/i82875p_edac.c532
2 files changed, 831 insertions, 0 deletions
diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c
new file mode 100644
index 000000000000..bfb7ae02e379
--- /dev/null
+++ b/drivers/edac/i82860_edac.c
@@ -0,0 +1,299 @@
1/*
2 * Intel 82860 Memory Controller kernel module
3 * (C) 2005 Red Hat (http://www.redhat.com)
4 * This file may be distributed under the terms of the
5 * GNU General Public License.
6 *
7 * Written by Ben Woodard <woodard@redhat.com>
8 * shamelessly copied from and based upon the edac_i82875 driver
9 * by Thayne Harbaugh of Linux Networx. (http://lnxi.com)
10 */
11
12
13#include <linux/config.h>
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/pci.h>
17#include <linux/pci_ids.h>
18#include <linux/slab.h>
19#include "edac_mc.h"
20
21
22#ifndef PCI_DEVICE_ID_INTEL_82860_0
23#define PCI_DEVICE_ID_INTEL_82860_0 0x2531
24#endif /* PCI_DEVICE_ID_INTEL_82860_0 */
25
26#define I82860_MCHCFG 0x50
27#define I82860_GBA 0x60
28#define I82860_GBA_MASK 0x7FF
29#define I82860_GBA_SHIFT 24
30#define I82860_ERRSTS 0xC8
31#define I82860_EAP 0xE4
32#define I82860_DERRCTL_STS 0xE2
33
34enum i82860_chips {
35 I82860 = 0,
36};
37
38struct i82860_dev_info {
39 const char *ctl_name;
40};
41
42struct i82860_error_info {
43 u16 errsts;
44 u32 eap;
45 u16 derrsyn;
46 u16 errsts2;
47};
48
49static const struct i82860_dev_info i82860_devs[] = {
50 [I82860] = {
51 .ctl_name = "i82860"},
52};
53
54static struct pci_dev *mci_pdev = NULL; /* init dev: in case that AGP code
55 has already registered driver */
56
57static int i82860_registered = 1;
58
59static void i82860_get_error_info (struct mem_ctl_info *mci,
60 struct i82860_error_info *info)
61{
62 /*
63 * This is a mess because there is no atomic way to read all the
64 * registers at once and the registers can transition from CE being
65 * overwritten by UE.
66 */
67 pci_read_config_word(mci->pdev, I82860_ERRSTS, &info->errsts);
68 pci_read_config_dword(mci->pdev, I82860_EAP, &info->eap);
69 pci_read_config_word(mci->pdev, I82860_DERRCTL_STS, &info->derrsyn);
70 pci_read_config_word(mci->pdev, I82860_ERRSTS, &info->errsts2);
71
72 pci_write_bits16(mci->pdev, I82860_ERRSTS, 0x0003, 0x0003);
73
74 /*
75 * If the error is the same for both reads then the first set of reads
76 * is valid. If there is a change then there is a CE no info and the
77 * second set of reads is valid and should be UE info.
78 */
79 if (!(info->errsts2 & 0x0003))
80 return;
81 if ((info->errsts ^ info->errsts2) & 0x0003) {
82 pci_read_config_dword(mci->pdev, I82860_EAP, &info->eap);
83 pci_read_config_word(mci->pdev, I82860_DERRCTL_STS,
84 &info->derrsyn);
85 }
86}
87
88static int i82860_process_error_info (struct mem_ctl_info *mci,
89 struct i82860_error_info *info, int handle_errors)
90{
91 int row;
92
93 if (!(info->errsts2 & 0x0003))
94 return 0;
95
96 if (!handle_errors)
97 return 1;
98
99 if ((info->errsts ^ info->errsts2) & 0x0003) {
100 edac_mc_handle_ce_no_info(mci, "UE overwrote CE");
101 info->errsts = info->errsts2;
102 }
103
104 info->eap >>= PAGE_SHIFT;
105 row = edac_mc_find_csrow_by_page(mci, info->eap);
106
107 if (info->errsts & 0x0002)
108 edac_mc_handle_ue(mci, info->eap, 0, row, "i82860 UE");
109 else
110 edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row,
111 0, "i82860 UE");
112
113 return 1;
114}
115
116static void i82860_check(struct mem_ctl_info *mci)
117{
118 struct i82860_error_info info;
119
120 debugf1("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
121 i82860_get_error_info(mci, &info);
122 i82860_process_error_info(mci, &info, 1);
123}
124
125static int i82860_probe1(struct pci_dev *pdev, int dev_idx)
126{
127 int rc = -ENODEV;
128 int index;
129 struct mem_ctl_info *mci = NULL;
130 unsigned long last_cumul_size;
131
132 u16 mchcfg_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */
133
134 /* RDRAM has channels but these don't map onto the abstractions that
135 edac uses.
136 The device groups from the GRA registers seem to map reasonably
137 well onto the notion of a chip select row.
138 There are 16 GRA registers and since the name is associated with
139 the channel and the GRA registers map to physical devices so we are
140 going to make 1 channel for group.
141 */
142 mci = edac_mc_alloc(0, 16, 1);
143 if (!mci)
144 return -ENOMEM;
145
146 debugf3("MC: " __FILE__ ": %s(): init mci\n", __func__);
147
148 mci->pdev = pdev;
149 mci->mtype_cap = MEM_FLAG_DDR;
150
151
152 mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
153 /* I"m not sure about this but I think that all RDRAM is SECDED */
154 mci->edac_cap = EDAC_FLAG_SECDED;
155 /* adjust FLAGS */
156
157 mci->mod_name = BS_MOD_STR;
158 mci->mod_ver = "$Revision: 1.1.2.6 $";
159 mci->ctl_name = i82860_devs[dev_idx].ctl_name;
160 mci->edac_check = i82860_check;
161 mci->ctl_page_to_phys = NULL;
162
163 pci_read_config_word(mci->pdev, I82860_MCHCFG, &mchcfg_ddim);
164 mchcfg_ddim = mchcfg_ddim & 0x180;
165
166 /*
167 * The group row boundary (GRA) reg values are boundary address
168 * for each DRAM row with a granularity of 16MB. GRA regs are
169 * cumulative; therefore GRA15 will contain the total memory contained
170 * in all eight rows.
171 */
172 for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) {
173 u16 value;
174 u32 cumul_size;
175 struct csrow_info *csrow = &mci->csrows[index];
176
177 pci_read_config_word(mci->pdev, I82860_GBA + index * 2,
178 &value);
179
180 cumul_size = (value & I82860_GBA_MASK) <<
181 (I82860_GBA_SHIFT - PAGE_SHIFT);
182 debugf3("MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n",
183 __func__, index, cumul_size);
184 if (cumul_size == last_cumul_size)
185 continue; /* not populated */
186
187 csrow->first_page = last_cumul_size;
188 csrow->last_page = cumul_size - 1;
189 csrow->nr_pages = cumul_size - last_cumul_size;
190 last_cumul_size = cumul_size;
191 csrow->grain = 1 << 12; /* I82860_EAP has 4KiB reolution */
192 csrow->mtype = MEM_RMBS;
193 csrow->dtype = DEV_UNKNOWN;
194 csrow->edac_mode = mchcfg_ddim ? EDAC_SECDED : EDAC_NONE;
195 }
196
197 /* clear counters */
198 pci_write_bits16(mci->pdev, I82860_ERRSTS, 0x0003, 0x0003);
199
200 if (edac_mc_add_mc(mci)) {
201 debugf3("MC: " __FILE__
202 ": %s(): failed edac_mc_add_mc()\n",
203 __func__);
204 edac_mc_free(mci);
205 } else {
206 /* get this far and it's successful */
207 debugf3("MC: " __FILE__ ": %s(): success\n", __func__);
208 rc = 0;
209 }
210 return rc;
211}
212
213/* returns count (>= 0), or negative on error */
214static int __devinit i82860_init_one(struct pci_dev *pdev,
215 const struct pci_device_id *ent)
216{
217 int rc;
218
219 debugf0("MC: " __FILE__ ": %s()\n", __func__);
220
221 printk(KERN_INFO "i82860 init one\n");
222 if(pci_enable_device(pdev) < 0)
223 return -EIO;
224 rc = i82860_probe1(pdev, ent->driver_data);
225 if(rc == 0)
226 mci_pdev = pci_dev_get(pdev);
227 return rc;
228}
229
230static void __devexit i82860_remove_one(struct pci_dev *pdev)
231{
232 struct mem_ctl_info *mci;
233
234 debugf0(__FILE__ ": %s()\n", __func__);
235
236 mci = edac_mc_find_mci_by_pdev(pdev);
237 if ((mci != NULL) && (edac_mc_del_mc(mci) == 0))
238 edac_mc_free(mci);
239}
240
241static const struct pci_device_id i82860_pci_tbl[] __devinitdata = {
242 {PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
243 I82860},
244 {0,} /* 0 terminated list. */
245};
246
247MODULE_DEVICE_TABLE(pci, i82860_pci_tbl);
248
249static struct pci_driver i82860_driver = {
250 .name = BS_MOD_STR,
251 .probe = i82860_init_one,
252 .remove = __devexit_p(i82860_remove_one),
253 .id_table = i82860_pci_tbl,
254};
255
256int __init i82860_init(void)
257{
258 int pci_rc;
259
260 debugf3("MC: " __FILE__ ": %s()\n", __func__);
261 if ((pci_rc = pci_register_driver(&i82860_driver)) < 0)
262 return pci_rc;
263
264 if (!mci_pdev) {
265 i82860_registered = 0;
266 mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
267 PCI_DEVICE_ID_INTEL_82860_0, NULL);
268 if (mci_pdev == NULL) {
269 debugf0("860 pci_get_device fail\n");
270 return -ENODEV;
271 }
272 pci_rc = i82860_init_one(mci_pdev, i82860_pci_tbl);
273 if (pci_rc < 0) {
274 debugf0("860 init fail\n");
275 pci_dev_put(mci_pdev);
276 return -ENODEV;
277 }
278 }
279 return 0;
280}
281
282static void __exit i82860_exit(void)
283{
284 debugf3("MC: " __FILE__ ": %s()\n", __func__);
285
286 pci_unregister_driver(&i82860_driver);
287 if (!i82860_registered) {
288 i82860_remove_one(mci_pdev);
289 pci_dev_put(mci_pdev);
290 }
291}
292
293module_init(i82860_init);
294module_exit(i82860_exit);
295
296MODULE_LICENSE("GPL");
297MODULE_AUTHOR
298 ("Red Hat Inc. (http://www.redhat.com.com) Ben Woodard <woodard@redhat.com>");
299MODULE_DESCRIPTION("ECC support for Intel 82860 memory hub controllers");
diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c
new file mode 100644
index 000000000000..79d14dfbcbdc
--- /dev/null
+++ b/drivers/edac/i82875p_edac.c
@@ -0,0 +1,532 @@
1/*
2 * Intel D82875P Memory Controller kernel module
3 * (C) 2003 Linux Networx (http://lnxi.com)
4 * This file may be distributed under the terms of the
5 * GNU General Public License.
6 *
7 * Written by Thayne Harbaugh
8 * Contributors:
9 * Wang Zhenyu at intel.com
10 *
11 * $Id: edac_i82875p.c,v 1.5.2.11 2005/10/05 00:43:44 dsp_llnl Exp $
12 *
13 * Note: E7210 appears same as D82875P - zhenyu.z.wang at intel.com
14 */
15
16
17#include <linux/config.h>
18#include <linux/module.h>
19#include <linux/init.h>
20
21#include <linux/pci.h>
22#include <linux/pci_ids.h>
23
24#include <linux/slab.h>
25
26#include "edac_mc.h"
27
28
29#ifndef PCI_DEVICE_ID_INTEL_82875_0
30#define PCI_DEVICE_ID_INTEL_82875_0 0x2578
31#endif /* PCI_DEVICE_ID_INTEL_82875_0 */
32
33#ifndef PCI_DEVICE_ID_INTEL_82875_6
34#define PCI_DEVICE_ID_INTEL_82875_6 0x257e
35#endif /* PCI_DEVICE_ID_INTEL_82875_6 */
36
37
38/* four csrows in dual channel, eight in single channel */
39#define I82875P_NR_CSROWS(nr_chans) (8/(nr_chans))
40
41
42/* Intel 82875p register addresses - device 0 function 0 - DRAM Controller */
43#define I82875P_EAP 0x58 /* Error Address Pointer (32b)
44 *
45 * 31:12 block address
46 * 11:0 reserved
47 */
48
49#define I82875P_DERRSYN 0x5c /* DRAM Error Syndrome (8b)
50 *
51 * 7:0 DRAM ECC Syndrome
52 */
53
54#define I82875P_DES 0x5d /* DRAM Error Status (8b)
55 *
56 * 7:1 reserved
57 * 0 Error channel 0/1
58 */
59
60#define I82875P_ERRSTS 0xc8 /* Error Status Register (16b)
61 *
62 * 15:10 reserved
63 * 9 non-DRAM lock error (ndlock)
64 * 8 Sftwr Generated SMI
65 * 7 ECC UE
66 * 6 reserved
67 * 5 MCH detects unimplemented cycle
68 * 4 AGP access outside GA
69 * 3 Invalid AGP access
70 * 2 Invalid GA translation table
71 * 1 Unsupported AGP command
72 * 0 ECC CE
73 */
74
75#define I82875P_ERRCMD 0xca /* Error Command (16b)
76 *
77 * 15:10 reserved
78 * 9 SERR on non-DRAM lock
79 * 8 SERR on ECC UE
80 * 7 SERR on ECC CE
81 * 6 target abort on high exception
82 * 5 detect unimplemented cyc
83 * 4 AGP access outside of GA
84 * 3 SERR on invalid AGP access
85 * 2 invalid translation table
86 * 1 SERR on unsupported AGP command
87 * 0 reserved
88 */
89
90
91/* Intel 82875p register addresses - device 6 function 0 - DRAM Controller */
92#define I82875P_PCICMD6 0x04 /* PCI Command Register (16b)
93 *
94 * 15:10 reserved
95 * 9 fast back-to-back - ro 0
96 * 8 SERR enable - ro 0
97 * 7 addr/data stepping - ro 0
98 * 6 parity err enable - ro 0
99 * 5 VGA palette snoop - ro 0
100 * 4 mem wr & invalidate - ro 0
101 * 3 special cycle - ro 0
102 * 2 bus master - ro 0
103 * 1 mem access dev6 - 0(dis),1(en)
104 * 0 IO access dev3 - 0(dis),1(en)
105 */
106
107#define I82875P_BAR6 0x10 /* Mem Delays Base ADDR Reg (32b)
108 *
109 * 31:12 mem base addr [31:12]
110 * 11:4 address mask - ro 0
111 * 3 prefetchable - ro 0(non),1(pre)
112 * 2:1 mem type - ro 0
113 * 0 mem space - ro 0
114 */
115
116/* Intel 82875p MMIO register space - device 0 function 0 - MMR space */
117
118#define I82875P_DRB_SHIFT 26 /* 64MiB grain */
119#define I82875P_DRB 0x00 /* DRAM Row Boundary (8b x 8)
120 *
121 * 7 reserved
122 * 6:0 64MiB row boundary addr
123 */
124
125#define I82875P_DRA 0x10 /* DRAM Row Attribute (4b x 8)
126 *
127 * 7 reserved
128 * 6:4 row attr row 1
129 * 3 reserved
130 * 2:0 row attr row 0
131 *
132 * 000 = 4KiB
133 * 001 = 8KiB
134 * 010 = 16KiB
135 * 011 = 32KiB
136 */
137
138#define I82875P_DRC 0x68 /* DRAM Controller Mode (32b)
139 *
140 * 31:30 reserved
141 * 29 init complete
142 * 28:23 reserved
143 * 22:21 nr chan 00=1,01=2
144 * 20 reserved
145 * 19:18 Data Integ Mode 00=none,01=ecc
146 * 17:11 reserved
147 * 10:8 refresh mode
148 * 7 reserved
149 * 6:4 mode select
150 * 3:2 reserved
151 * 1:0 DRAM type 01=DDR
152 */
153
154
155enum i82875p_chips {
156 I82875P = 0,
157};
158
159
160struct i82875p_pvt {
161 struct pci_dev *ovrfl_pdev;
162 void *ovrfl_window;
163};
164
165
166struct i82875p_dev_info {
167 const char *ctl_name;
168};
169
170
171struct i82875p_error_info {
172 u16 errsts;
173 u32 eap;
174 u8 des;
175 u8 derrsyn;
176 u16 errsts2;
177};
178
179
180static const struct i82875p_dev_info i82875p_devs[] = {
181 [I82875P] = {
182 .ctl_name = "i82875p"},
183};
184
185static struct pci_dev *mci_pdev = NULL; /* init dev: in case that AGP code
186 has already registered driver */
187static int i82875p_registered = 1;
188
189static void i82875p_get_error_info (struct mem_ctl_info *mci,
190 struct i82875p_error_info *info)
191{
192 /*
193 * This is a mess because there is no atomic way to read all the
194 * registers at once and the registers can transition from CE being
195 * overwritten by UE.
196 */
197 pci_read_config_word(mci->pdev, I82875P_ERRSTS, &info->errsts);
198 pci_read_config_dword(mci->pdev, I82875P_EAP, &info->eap);
199 pci_read_config_byte(mci->pdev, I82875P_DES, &info->des);
200 pci_read_config_byte(mci->pdev, I82875P_DERRSYN, &info->derrsyn);
201 pci_read_config_word(mci->pdev, I82875P_ERRSTS, &info->errsts2);
202
203 pci_write_bits16(mci->pdev, I82875P_ERRSTS, 0x0081, 0x0081);
204
205 /*
206 * If the error is the same then we can for both reads then
207 * the first set of reads is valid. If there is a change then
208 * there is a CE no info and the second set of reads is valid
209 * and should be UE info.
210 */
211 if (!(info->errsts2 & 0x0081))
212 return;
213 if ((info->errsts ^ info->errsts2) & 0x0081) {
214 pci_read_config_dword(mci->pdev, I82875P_EAP, &info->eap);
215 pci_read_config_byte(mci->pdev, I82875P_DES, &info->des);
216 pci_read_config_byte(mci->pdev, I82875P_DERRSYN,
217 &info->derrsyn);
218 }
219}
220
221static int i82875p_process_error_info (struct mem_ctl_info *mci,
222 struct i82875p_error_info *info, int handle_errors)
223{
224 int row, multi_chan;
225
226 multi_chan = mci->csrows[0].nr_channels - 1;
227
228 if (!(info->errsts2 & 0x0081))
229 return 0;
230
231 if (!handle_errors)
232 return 1;
233
234 if ((info->errsts ^ info->errsts2) & 0x0081) {
235 edac_mc_handle_ce_no_info(mci, "UE overwrote CE");
236 info->errsts = info->errsts2;
237 }
238
239 info->eap >>= PAGE_SHIFT;
240 row = edac_mc_find_csrow_by_page(mci, info->eap);
241
242 if (info->errsts & 0x0080)
243 edac_mc_handle_ue(mci, info->eap, 0, row, "i82875p UE");
244 else
245 edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row,
246 multi_chan ? (info->des & 0x1) : 0,
247 "i82875p CE");
248
249 return 1;
250}
251
252
253static void i82875p_check(struct mem_ctl_info *mci)
254{
255 struct i82875p_error_info info;
256
257 debugf1("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
258 i82875p_get_error_info(mci, &info);
259 i82875p_process_error_info(mci, &info, 1);
260}
261
262
263#ifdef CONFIG_PROC_FS
264extern int pci_proc_attach_device(struct pci_dev *);
265#endif
266
267static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
268{
269 int rc = -ENODEV;
270 int index;
271 struct mem_ctl_info *mci = NULL;
272 struct i82875p_pvt *pvt = NULL;
273 unsigned long last_cumul_size;
274 struct pci_dev *ovrfl_pdev;
275 void __iomem *ovrfl_window = NULL;
276
277 u32 drc;
278 u32 drc_chan; /* Number of channels 0=1chan,1=2chan */
279 u32 nr_chans;
280 u32 drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */
281
282 debugf0("MC: " __FILE__ ": %s()\n", __func__);
283
284 ovrfl_pdev = pci_find_device(PCI_VEND_DEV(INTEL, 82875_6), NULL);
285
286 if (!ovrfl_pdev) {
287 /*
288 * Intel tells BIOS developers to hide device 6 which
289 * configures the overflow device access containing
290 * the DRBs - this is where we expose device 6.
291 * http://www.x86-secret.com/articles/tweak/pat/patsecrets-2.htm
292 */
293 pci_write_bits8(pdev, 0xf4, 0x2, 0x2);
294 ovrfl_pdev =
295 pci_scan_single_device(pdev->bus, PCI_DEVFN(6, 0));
296 if (!ovrfl_pdev)
297 goto fail;
298 }
299#ifdef CONFIG_PROC_FS
300 if (!ovrfl_pdev->procent && pci_proc_attach_device(ovrfl_pdev)) {
301 printk(KERN_ERR "MC: " __FILE__
302 ": %s(): Failed to attach overflow device\n",
303 __func__);
304 goto fail;
305 }
306#endif /* CONFIG_PROC_FS */
307 if (pci_enable_device(ovrfl_pdev)) {
308 printk(KERN_ERR "MC: " __FILE__
309 ": %s(): Failed to enable overflow device\n",
310 __func__);
311 goto fail;
312 }
313
314 if (pci_request_regions(ovrfl_pdev, pci_name(ovrfl_pdev))) {
315#ifdef CORRECT_BIOS
316 goto fail;
317#endif
318 }
319 /* cache is irrelevant for PCI bus reads/writes */
320 ovrfl_window = ioremap_nocache(pci_resource_start(ovrfl_pdev, 0),
321 pci_resource_len(ovrfl_pdev, 0));
322
323 if (!ovrfl_window) {
324 printk(KERN_ERR "MC: " __FILE__
325 ": %s(): Failed to ioremap bar6\n", __func__);
326 goto fail;
327 }
328
329 /* need to find out the number of channels */
330 drc = readl(ovrfl_window + I82875P_DRC);
331 drc_chan = ((drc >> 21) & 0x1);
332 nr_chans = drc_chan + 1;
333 drc_ddim = (drc >> 18) & 0x1;
334
335 mci = edac_mc_alloc(sizeof(*pvt), I82875P_NR_CSROWS(nr_chans),
336 nr_chans);
337
338 if (!mci) {
339 rc = -ENOMEM;
340 goto fail;
341 }
342
343 debugf3("MC: " __FILE__ ": %s(): init mci\n", __func__);
344
345 mci->pdev = pdev;
346 mci->mtype_cap = MEM_FLAG_DDR;
347
348 mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
349 mci->edac_cap = EDAC_FLAG_UNKNOWN;
350 /* adjust FLAGS */
351
352 mci->mod_name = BS_MOD_STR;
353 mci->mod_ver = "$Revision: 1.5.2.11 $";
354 mci->ctl_name = i82875p_devs[dev_idx].ctl_name;
355 mci->edac_check = i82875p_check;
356 mci->ctl_page_to_phys = NULL;
357
358 debugf3("MC: " __FILE__ ": %s(): init pvt\n", __func__);
359
360 pvt = (struct i82875p_pvt *) mci->pvt_info;
361 pvt->ovrfl_pdev = ovrfl_pdev;
362 pvt->ovrfl_window = ovrfl_window;
363
364 /*
365 * The dram row boundary (DRB) reg values are boundary address
366 * for each DRAM row with a granularity of 32 or 64MB (single/dual
367 * channel operation). DRB regs are cumulative; therefore DRB7 will
368 * contain the total memory contained in all eight rows.
369 */
370 for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) {
371 u8 value;
372 u32 cumul_size;
373 struct csrow_info *csrow = &mci->csrows[index];
374
375 value = readb(ovrfl_window + I82875P_DRB + index);
376 cumul_size = value << (I82875P_DRB_SHIFT - PAGE_SHIFT);
377 debugf3("MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n",
378 __func__, index, cumul_size);
379 if (cumul_size == last_cumul_size)
380 continue; /* not populated */
381
382 csrow->first_page = last_cumul_size;
383 csrow->last_page = cumul_size - 1;
384 csrow->nr_pages = cumul_size - last_cumul_size;
385 last_cumul_size = cumul_size;
386 csrow->grain = 1 << 12; /* I82875P_EAP has 4KiB reolution */
387 csrow->mtype = MEM_DDR;
388 csrow->dtype = DEV_UNKNOWN;
389 csrow->edac_mode = drc_ddim ? EDAC_SECDED : EDAC_NONE;
390 }
391
392 /* clear counters */
393 pci_write_bits16(mci->pdev, I82875P_ERRSTS, 0x0081, 0x0081);
394
395 if (edac_mc_add_mc(mci)) {
396 debugf3("MC: " __FILE__
397 ": %s(): failed edac_mc_add_mc()\n", __func__);
398 goto fail;
399 }
400
401 /* get this far and it's successful */
402 debugf3("MC: " __FILE__ ": %s(): success\n", __func__);
403 return 0;
404
405 fail:
406 if (mci)
407 edac_mc_free(mci);
408
409 if (ovrfl_window)
410 iounmap(ovrfl_window);
411
412 if (ovrfl_pdev) {
413 pci_release_regions(ovrfl_pdev);
414 pci_disable_device(ovrfl_pdev);
415 }
416
417 /* NOTE: the ovrfl proc entry and pci_dev are intentionally left */
418 return rc;
419}
420
421
422/* returns count (>= 0), or negative on error */
423static int __devinit i82875p_init_one(struct pci_dev *pdev,
424 const struct pci_device_id *ent)
425{
426 int rc;
427
428 debugf0("MC: " __FILE__ ": %s()\n", __func__);
429
430 printk(KERN_INFO "i82875p init one\n");
431 if(pci_enable_device(pdev) < 0)
432 return -EIO;
433 rc = i82875p_probe1(pdev, ent->driver_data);
434 if (mci_pdev == NULL)
435 mci_pdev = pci_dev_get(pdev);
436 return rc;
437}
438
439
440static void __devexit i82875p_remove_one(struct pci_dev *pdev)
441{
442 struct mem_ctl_info *mci;
443 struct i82875p_pvt *pvt = NULL;
444
445 debugf0(__FILE__ ": %s()\n", __func__);
446
447 if ((mci = edac_mc_find_mci_by_pdev(pdev)) == NULL)
448 return;
449
450 pvt = (struct i82875p_pvt *) mci->pvt_info;
451 if (pvt->ovrfl_window)
452 iounmap(pvt->ovrfl_window);
453
454 if (pvt->ovrfl_pdev) {
455#ifdef CORRECT_BIOS
456 pci_release_regions(pvt->ovrfl_pdev);
457#endif /*CORRECT_BIOS */
458 pci_disable_device(pvt->ovrfl_pdev);
459 pci_dev_put(pvt->ovrfl_pdev);
460 }
461
462 if (edac_mc_del_mc(mci))
463 return;
464
465 edac_mc_free(mci);
466}
467
468
469static const struct pci_device_id i82875p_pci_tbl[] __devinitdata = {
470 {PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
471 I82875P},
472 {0,} /* 0 terminated list. */
473};
474
475MODULE_DEVICE_TABLE(pci, i82875p_pci_tbl);
476
477
478static struct pci_driver i82875p_driver = {
479 .name = BS_MOD_STR,
480 .probe = i82875p_init_one,
481 .remove = __devexit_p(i82875p_remove_one),
482 .id_table = i82875p_pci_tbl,
483};
484
485
486int __init i82875p_init(void)
487{
488 int pci_rc;
489
490 debugf3("MC: " __FILE__ ": %s()\n", __func__);
491 pci_rc = pci_register_driver(&i82875p_driver);
492 if (pci_rc < 0)
493 return pci_rc;
494 if (mci_pdev == NULL) {
495 i82875p_registered = 0;
496 mci_pdev =
497 pci_get_device(PCI_VENDOR_ID_INTEL,
498 PCI_DEVICE_ID_INTEL_82875_0, NULL);
499 if (!mci_pdev) {
500 debugf0("875p pci_get_device fail\n");
501 return -ENODEV;
502 }
503 pci_rc = i82875p_init_one(mci_pdev, i82875p_pci_tbl);
504 if (pci_rc < 0) {
505 debugf0("875p init fail\n");
506 pci_dev_put(mci_pdev);
507 return -ENODEV;
508 }
509 }
510 return 0;
511}
512
513
514static void __exit i82875p_exit(void)
515{
516 debugf3("MC: " __FILE__ ": %s()\n", __func__);
517
518 pci_unregister_driver(&i82875p_driver);
519 if (!i82875p_registered) {
520 i82875p_remove_one(mci_pdev);
521 pci_dev_put(mci_pdev);
522 }
523}
524
525
526module_init(i82875p_init);
527module_exit(i82875p_exit);
528
529
530MODULE_LICENSE("GPL");
531MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh");
532MODULE_DESCRIPTION("MC support for Intel 82875 memory hub controllers");