linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / drivers / edac / i82860_edac.c
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
34 enum i82860_chips {
35         I82860 = 0,
36 };
37
38 struct i82860_dev_info {
39         const char *ctl_name;
40 };
41
42 struct i82860_error_info {
43         u16 errsts;
44         u32 eap;
45         u16 derrsyn;
46         u16 errsts2;
47 };
48
49 static const struct i82860_dev_info i82860_devs[] = {
50         [I82860] = {
51                     .ctl_name = "i82860"},
52 };
53
54 static struct pci_dev *mci_pdev = NULL; /* init dev: in case that AGP code
55                                            has already registered driver */
56
57 static int i82860_registered = 1;
58
59 static 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
88 static 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
116 static 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
125 static 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 */
214 static 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
230 static 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
241 static 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
247 MODULE_DEVICE_TABLE(pci, i82860_pci_tbl);
248
249 static 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
256 static int __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
282 static 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
293 module_init(i82860_init);
294 module_exit(i82860_exit);
295
296 MODULE_LICENSE("GPL");
297 MODULE_AUTHOR
298     ("Red Hat Inc. (http://www.redhat.com.com) Ben Woodard <woodard@redhat.com>");
299 MODULE_DESCRIPTION("ECC support for Intel 82860 memory hub controllers");