Merge ../linux-2.6
[deliverable/linux.git] / drivers / edac / i82860_edac.c
CommitLineData
0d88a10e
AC
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
0d88a10e
AC
12#include <linux/config.h>
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/pci.h>
16#include <linux/pci_ids.h>
17#include <linux/slab.h>
18#include "edac_mc.h"
19
537fba28 20#define i82860_printk(level, fmt, arg...) \
e7ecd891 21 edac_printk(level, "i82860", fmt, ##arg)
537fba28
DP
22
23#define i82860_mc_printk(mci, level, fmt, arg...) \
e7ecd891 24 edac_mc_chipset_printk(mci, level, "i82860", fmt, ##arg)
537fba28 25
0d88a10e
AC
26#ifndef PCI_DEVICE_ID_INTEL_82860_0
27#define PCI_DEVICE_ID_INTEL_82860_0 0x2531
28#endif /* PCI_DEVICE_ID_INTEL_82860_0 */
29
30#define I82860_MCHCFG 0x50
31#define I82860_GBA 0x60
32#define I82860_GBA_MASK 0x7FF
33#define I82860_GBA_SHIFT 24
34#define I82860_ERRSTS 0xC8
35#define I82860_EAP 0xE4
36#define I82860_DERRCTL_STS 0xE2
37
38enum i82860_chips {
39 I82860 = 0,
40};
41
42struct i82860_dev_info {
43 const char *ctl_name;
44};
45
46struct i82860_error_info {
47 u16 errsts;
48 u32 eap;
49 u16 derrsyn;
50 u16 errsts2;
51};
52
53static const struct i82860_dev_info i82860_devs[] = {
54 [I82860] = {
e7ecd891
DP
55 .ctl_name = "i82860"
56 },
0d88a10e
AC
57};
58
59static struct pci_dev *mci_pdev = NULL; /* init dev: in case that AGP code
e7ecd891
DP
60 * has already registered driver
61 */
0d88a10e 62
e7ecd891 63static void i82860_get_error_info(struct mem_ctl_info *mci,
0d88a10e
AC
64 struct i82860_error_info *info)
65{
66 /*
67 * This is a mess because there is no atomic way to read all the
68 * registers at once and the registers can transition from CE being
69 * overwritten by UE.
70 */
71 pci_read_config_word(mci->pdev, I82860_ERRSTS, &info->errsts);
72 pci_read_config_dword(mci->pdev, I82860_EAP, &info->eap);
73 pci_read_config_word(mci->pdev, I82860_DERRCTL_STS, &info->derrsyn);
74 pci_read_config_word(mci->pdev, I82860_ERRSTS, &info->errsts2);
75
76 pci_write_bits16(mci->pdev, I82860_ERRSTS, 0x0003, 0x0003);
77
78 /*
79 * If the error is the same for both reads then the first set of reads
80 * is valid. If there is a change then there is a CE no info and the
81 * second set of reads is valid and should be UE info.
82 */
83 if (!(info->errsts2 & 0x0003))
84 return;
e7ecd891 85
0d88a10e
AC
86 if ((info->errsts ^ info->errsts2) & 0x0003) {
87 pci_read_config_dword(mci->pdev, I82860_EAP, &info->eap);
88 pci_read_config_word(mci->pdev, I82860_DERRCTL_STS,
e7ecd891 89 &info->derrsyn);
0d88a10e
AC
90 }
91}
92
e7ecd891 93static int i82860_process_error_info(struct mem_ctl_info *mci,
0d88a10e
AC
94 struct i82860_error_info *info, int handle_errors)
95{
96 int row;
97
98 if (!(info->errsts2 & 0x0003))
99 return 0;
100
101 if (!handle_errors)
102 return 1;
103
104 if ((info->errsts ^ info->errsts2) & 0x0003) {
105 edac_mc_handle_ce_no_info(mci, "UE overwrote CE");
106 info->errsts = info->errsts2;
107 }
108
109 info->eap >>= PAGE_SHIFT;
110 row = edac_mc_find_csrow_by_page(mci, info->eap);
111
112 if (info->errsts & 0x0002)
113 edac_mc_handle_ue(mci, info->eap, 0, row, "i82860 UE");
114 else
e7ecd891
DP
115 edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row, 0,
116 "i82860 UE");
0d88a10e
AC
117
118 return 1;
119}
120
121static void i82860_check(struct mem_ctl_info *mci)
122{
123 struct i82860_error_info info;
124
537fba28 125 debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
0d88a10e
AC
126 i82860_get_error_info(mci, &info);
127 i82860_process_error_info(mci, &info, 1);
128}
129
130static int i82860_probe1(struct pci_dev *pdev, int dev_idx)
131{
132 int rc = -ENODEV;
133 int index;
134 struct mem_ctl_info *mci = NULL;
135 unsigned long last_cumul_size;
749ede57 136 struct i82860_error_info discard;
0d88a10e
AC
137
138 u16 mchcfg_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */
139
140 /* RDRAM has channels but these don't map onto the abstractions that
141 edac uses.
142 The device groups from the GRA registers seem to map reasonably
143 well onto the notion of a chip select row.
144 There are 16 GRA registers and since the name is associated with
145 the channel and the GRA registers map to physical devices so we are
146 going to make 1 channel for group.
147 */
148 mci = edac_mc_alloc(0, 16, 1);
e7ecd891 149
0d88a10e
AC
150 if (!mci)
151 return -ENOMEM;
152
537fba28 153 debugf3("%s(): init mci\n", __func__);
0d88a10e
AC
154 mci->pdev = pdev;
155 mci->mtype_cap = MEM_FLAG_DDR;
156
0d88a10e
AC
157 mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
158 /* I"m not sure about this but I think that all RDRAM is SECDED */
159 mci->edac_cap = EDAC_FLAG_SECDED;
160 /* adjust FLAGS */
161
680cbbbb 162 mci->mod_name = EDAC_MOD_STR;
0d88a10e
AC
163 mci->mod_ver = "$Revision: 1.1.2.6 $";
164 mci->ctl_name = i82860_devs[dev_idx].ctl_name;
165 mci->edac_check = i82860_check;
166 mci->ctl_page_to_phys = NULL;
167
168 pci_read_config_word(mci->pdev, I82860_MCHCFG, &mchcfg_ddim);
169 mchcfg_ddim = mchcfg_ddim & 0x180;
170
171 /*
172 * The group row boundary (GRA) reg values are boundary address
173 * for each DRAM row with a granularity of 16MB. GRA regs are
174 * cumulative; therefore GRA15 will contain the total memory contained
175 * in all eight rows.
176 */
177 for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) {
178 u16 value;
179 u32 cumul_size;
180 struct csrow_info *csrow = &mci->csrows[index];
181
182 pci_read_config_word(mci->pdev, I82860_GBA + index * 2,
e7ecd891 183 &value);
0d88a10e
AC
184
185 cumul_size = (value & I82860_GBA_MASK) <<
186 (I82860_GBA_SHIFT - PAGE_SHIFT);
537fba28
DP
187 debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
188 cumul_size);
e7ecd891 189
0d88a10e
AC
190 if (cumul_size == last_cumul_size)
191 continue; /* not populated */
192
193 csrow->first_page = last_cumul_size;
194 csrow->last_page = cumul_size - 1;
195 csrow->nr_pages = cumul_size - last_cumul_size;
196 last_cumul_size = cumul_size;
e7ecd891 197 csrow->grain = 1 << 12; /* I82860_EAP has 4KiB reolution */
0d88a10e
AC
198 csrow->mtype = MEM_RMBS;
199 csrow->dtype = DEV_UNKNOWN;
200 csrow->edac_mode = mchcfg_ddim ? EDAC_SECDED : EDAC_NONE;
201 }
202
749ede57 203 i82860_get_error_info(mci, &discard); /* clear counters */
0d88a10e
AC
204
205 if (edac_mc_add_mc(mci)) {
537fba28 206 debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
0d88a10e
AC
207 edac_mc_free(mci);
208 } else {
209 /* get this far and it's successful */
537fba28 210 debugf3("%s(): success\n", __func__);
0d88a10e
AC
211 rc = 0;
212 }
e7ecd891 213
0d88a10e
AC
214 return rc;
215}
216
217/* returns count (>= 0), or negative on error */
218static int __devinit i82860_init_one(struct pci_dev *pdev,
e7ecd891 219 const struct pci_device_id *ent)
0d88a10e
AC
220{
221 int rc;
222
537fba28 223 debugf0("%s()\n", __func__);
537fba28 224 i82860_printk(KERN_INFO, "i82860 init one\n");
e7ecd891
DP
225
226 if (pci_enable_device(pdev) < 0)
0d88a10e 227 return -EIO;
e7ecd891 228
0d88a10e 229 rc = i82860_probe1(pdev, ent->driver_data);
e7ecd891
DP
230
231 if (rc == 0)
0d88a10e 232 mci_pdev = pci_dev_get(pdev);
e7ecd891 233
0d88a10e
AC
234 return rc;
235}
236
237static void __devexit i82860_remove_one(struct pci_dev *pdev)
238{
239 struct mem_ctl_info *mci;
240
537fba28 241 debugf0("%s()\n", __func__);
0d88a10e 242
18dbc337
DP
243 if ((mci = edac_mc_del_mc(pdev)) == NULL)
244 return;
245
246 edac_mc_free(mci);
0d88a10e
AC
247}
248
249static const struct pci_device_id i82860_pci_tbl[] __devinitdata = {
e7ecd891
DP
250 {
251 PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
252 I82860
253 },
254 {
255 0,
256 } /* 0 terminated list. */
0d88a10e
AC
257};
258
259MODULE_DEVICE_TABLE(pci, i82860_pci_tbl);
260
261static struct pci_driver i82860_driver = {
680cbbbb 262 .name = EDAC_MOD_STR,
0d88a10e
AC
263 .probe = i82860_init_one,
264 .remove = __devexit_p(i82860_remove_one),
265 .id_table = i82860_pci_tbl,
266};
267
da9bb1d2 268static int __init i82860_init(void)
0d88a10e
AC
269{
270 int pci_rc;
271
537fba28 272 debugf3("%s()\n", __func__);
e7ecd891 273
0d88a10e 274 if ((pci_rc = pci_register_driver(&i82860_driver)) < 0)
e8a491b4 275 goto fail0;
0d88a10e
AC
276
277 if (!mci_pdev) {
0d88a10e 278 mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
e7ecd891
DP
279 PCI_DEVICE_ID_INTEL_82860_0, NULL);
280
0d88a10e
AC
281 if (mci_pdev == NULL) {
282 debugf0("860 pci_get_device fail\n");
e8a491b4
DP
283 pci_rc = -ENODEV;
284 goto fail1;
0d88a10e 285 }
e7ecd891 286
0d88a10e 287 pci_rc = i82860_init_one(mci_pdev, i82860_pci_tbl);
e7ecd891 288
0d88a10e
AC
289 if (pci_rc < 0) {
290 debugf0("860 init fail\n");
e8a491b4
DP
291 pci_rc = -ENODEV;
292 goto fail1;
0d88a10e
AC
293 }
294 }
e7ecd891 295
0d88a10e 296 return 0;
e8a491b4
DP
297
298fail1:
299 pci_unregister_driver(&i82860_driver);
300
301fail0:
302 if (mci_pdev != NULL)
303 pci_dev_put(mci_pdev);
304
305 return pci_rc;
0d88a10e
AC
306}
307
308static void __exit i82860_exit(void)
309{
537fba28 310 debugf3("%s()\n", __func__);
0d88a10e
AC
311
312 pci_unregister_driver(&i82860_driver);
e8a491b4
DP
313
314 if (mci_pdev != NULL)
0d88a10e 315 pci_dev_put(mci_pdev);
0d88a10e
AC
316}
317
318module_init(i82860_init);
319module_exit(i82860_exit);
320
321MODULE_LICENSE("GPL");
e7ecd891
DP
322MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com) "
323 "Ben Woodard <woodard@redhat.com>");
0d88a10e 324MODULE_DESCRIPTION("ECC support for Intel 82860 memory hub controllers");
This page took 0.104831 seconds and 5 git commands to generate.