blob: c0088ba9672b754429d0bcd8bea19329f36c4064 [file] [log] [blame]
Alan Cox0d88a102006-01-18 17:44:10 -08001/*
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
Alan Cox0d88a102006-01-18 17:44:10 -080012#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/pci.h>
15#include <linux/pci_ids.h>
16#include <linux/slab.h>
Hitoshi Mitakec3c52bc2008-04-29 01:03:18 -070017#include <linux/edac.h>
Douglas Thompson20bcb7a2007-07-19 01:49:47 -070018#include "edac_core.h"
Alan Cox0d88a102006-01-18 17:44:10 -080019
Douglas Thompson20bcb7a2007-07-19 01:49:47 -070020#define I82860_REVISION " Ver: 2.0.2 " __DATE__
Doug Thompson929a40e2006-07-01 04:35:45 -070021#define EDAC_MOD_STR "i82860_edac"
Doug Thompson37f04582006-06-30 01:56:07 -070022
Dave Peterson537fba22006-03-26 01:38:40 -080023#define i82860_printk(level, fmt, arg...) \
Dave Petersone7ecd892006-03-26 01:38:52 -080024 edac_printk(level, "i82860", fmt, ##arg)
Dave Peterson537fba22006-03-26 01:38:40 -080025
26#define i82860_mc_printk(mci, level, fmt, arg...) \
Dave Petersone7ecd892006-03-26 01:38:52 -080027 edac_mc_chipset_printk(mci, level, "i82860", fmt, ##arg)
Dave Peterson537fba22006-03-26 01:38:40 -080028
Alan Cox0d88a102006-01-18 17:44:10 -080029#ifndef PCI_DEVICE_ID_INTEL_82860_0
30#define PCI_DEVICE_ID_INTEL_82860_0 0x2531
31#endif /* PCI_DEVICE_ID_INTEL_82860_0 */
32
33#define I82860_MCHCFG 0x50
34#define I82860_GBA 0x60
35#define I82860_GBA_MASK 0x7FF
36#define I82860_GBA_SHIFT 24
37#define I82860_ERRSTS 0xC8
38#define I82860_EAP 0xE4
39#define I82860_DERRCTL_STS 0xE2
40
41enum i82860_chips {
42 I82860 = 0,
43};
44
45struct i82860_dev_info {
46 const char *ctl_name;
47};
48
49struct i82860_error_info {
50 u16 errsts;
51 u32 eap;
52 u16 derrsyn;
53 u16 errsts2;
54};
55
56static const struct i82860_dev_info i82860_devs[] = {
57 [I82860] = {
Douglas Thompson052dfb42007-07-19 01:50:13 -070058 .ctl_name = "i82860"},
Alan Cox0d88a102006-01-18 17:44:10 -080059};
60
Douglas Thompsonf0440912007-07-19 01:50:19 -070061static struct pci_dev *mci_pdev; /* init dev: in case that AGP code
Dave Petersone7ecd892006-03-26 01:38:52 -080062 * has already registered driver
63 */
Dave Jiang456a2f92007-07-19 01:50:10 -070064static struct edac_pci_ctl_info *i82860_pci;
Alan Cox0d88a102006-01-18 17:44:10 -080065
Dave Petersone7ecd892006-03-26 01:38:52 -080066static void i82860_get_error_info(struct mem_ctl_info *mci,
Douglas Thompson052dfb42007-07-19 01:50:13 -070067 struct i82860_error_info *info)
Alan Cox0d88a102006-01-18 17:44:10 -080068{
Doug Thompson37f04582006-06-30 01:56:07 -070069 struct pci_dev *pdev;
70
71 pdev = to_pci_dev(mci->dev);
72
Alan Cox0d88a102006-01-18 17:44:10 -080073 /*
74 * This is a mess because there is no atomic way to read all the
75 * registers at once and the registers can transition from CE being
76 * overwritten by UE.
77 */
Doug Thompson37f04582006-06-30 01:56:07 -070078 pci_read_config_word(pdev, I82860_ERRSTS, &info->errsts);
79 pci_read_config_dword(pdev, I82860_EAP, &info->eap);
80 pci_read_config_word(pdev, I82860_DERRCTL_STS, &info->derrsyn);
81 pci_read_config_word(pdev, I82860_ERRSTS, &info->errsts2);
Alan Cox0d88a102006-01-18 17:44:10 -080082
Doug Thompson37f04582006-06-30 01:56:07 -070083 pci_write_bits16(pdev, I82860_ERRSTS, 0x0003, 0x0003);
Alan Cox0d88a102006-01-18 17:44:10 -080084
85 /*
86 * If the error is the same for both reads then the first set of reads
87 * is valid. If there is a change then there is a CE no info and the
88 * second set of reads is valid and should be UE info.
89 */
90 if (!(info->errsts2 & 0x0003))
91 return;
Dave Petersone7ecd892006-03-26 01:38:52 -080092
Alan Cox0d88a102006-01-18 17:44:10 -080093 if ((info->errsts ^ info->errsts2) & 0x0003) {
Doug Thompson37f04582006-06-30 01:56:07 -070094 pci_read_config_dword(pdev, I82860_EAP, &info->eap);
Dave Jiangb4e8b372007-07-19 01:50:04 -070095 pci_read_config_word(pdev, I82860_DERRCTL_STS, &info->derrsyn);
Alan Cox0d88a102006-01-18 17:44:10 -080096 }
97}
98
Dave Petersone7ecd892006-03-26 01:38:52 -080099static int i82860_process_error_info(struct mem_ctl_info *mci,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700100 struct i82860_error_info *info,
101 int handle_errors)
Alan Cox0d88a102006-01-18 17:44:10 -0800102{
103 int row;
104
105 if (!(info->errsts2 & 0x0003))
106 return 0;
107
108 if (!handle_errors)
109 return 1;
110
111 if ((info->errsts ^ info->errsts2) & 0x0003) {
112 edac_mc_handle_ce_no_info(mci, "UE overwrote CE");
113 info->errsts = info->errsts2;
114 }
115
116 info->eap >>= PAGE_SHIFT;
117 row = edac_mc_find_csrow_by_page(mci, info->eap);
118
119 if (info->errsts & 0x0002)
120 edac_mc_handle_ue(mci, info->eap, 0, row, "i82860 UE");
121 else
Dave Petersone7ecd892006-03-26 01:38:52 -0800122 edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row, 0,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700123 "i82860 UE");
Alan Cox0d88a102006-01-18 17:44:10 -0800124
125 return 1;
126}
127
128static void i82860_check(struct mem_ctl_info *mci)
129{
130 struct i82860_error_info info;
131
Dave Peterson537fba22006-03-26 01:38:40 -0800132 debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
Alan Cox0d88a102006-01-18 17:44:10 -0800133 i82860_get_error_info(mci, &info);
134 i82860_process_error_info(mci, &info, 1);
135}
136
Doug Thompson13189522006-06-30 01:56:08 -0700137static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev)
138{
139 unsigned long last_cumul_size;
Dave Jiangb4e8b372007-07-19 01:50:04 -0700140 u16 mchcfg_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */
Doug Thompson13189522006-06-30 01:56:08 -0700141 u16 value;
142 u32 cumul_size;
143 struct csrow_info *csrow;
144 int index;
145
146 pci_read_config_word(pdev, I82860_MCHCFG, &mchcfg_ddim);
147 mchcfg_ddim = mchcfg_ddim & 0x180;
148 last_cumul_size = 0;
149
150 /* The group row boundary (GRA) reg values are boundary address
151 * for each DRAM row with a granularity of 16MB. GRA regs are
152 * cumulative; therefore GRA15 will contain the total memory contained
153 * in all eight rows.
154 */
155 for (index = 0; index < mci->nr_csrows; index++) {
156 csrow = &mci->csrows[index];
157 pci_read_config_word(pdev, I82860_GBA + index * 2, &value);
158 cumul_size = (value & I82860_GBA_MASK) <<
Douglas Thompson052dfb42007-07-19 01:50:13 -0700159 (I82860_GBA_SHIFT - PAGE_SHIFT);
Doug Thompson13189522006-06-30 01:56:08 -0700160 debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
161 cumul_size);
162
163 if (cumul_size == last_cumul_size)
164 continue; /* not populated */
165
166 csrow->first_page = last_cumul_size;
167 csrow->last_page = cumul_size - 1;
168 csrow->nr_pages = cumul_size - last_cumul_size;
169 last_cumul_size = cumul_size;
170 csrow->grain = 1 << 12; /* I82860_EAP has 4KiB reolution */
171 csrow->mtype = MEM_RMBS;
172 csrow->dtype = DEV_UNKNOWN;
173 csrow->edac_mode = mchcfg_ddim ? EDAC_SECDED : EDAC_NONE;
174 }
175}
176
Alan Cox0d88a102006-01-18 17:44:10 -0800177static int i82860_probe1(struct pci_dev *pdev, int dev_idx)
178{
Doug Thompson13189522006-06-30 01:56:08 -0700179 struct mem_ctl_info *mci;
Dave Peterson749ede52006-03-26 01:38:45 -0800180 struct i82860_error_info discard;
Alan Cox0d88a102006-01-18 17:44:10 -0800181
Alan Cox0d88a102006-01-18 17:44:10 -0800182 /* RDRAM has channels but these don't map onto the abstractions that
183 edac uses.
184 The device groups from the GRA registers seem to map reasonably
185 well onto the notion of a chip select row.
186 There are 16 GRA registers and since the name is associated with
187 the channel and the GRA registers map to physical devices so we are
188 going to make 1 channel for group.
189 */
Doug Thompsonb8f6f972007-07-19 01:50:26 -0700190 mci = edac_mc_alloc(0, 16, 1, 0);
Dave Petersone7ecd892006-03-26 01:38:52 -0800191
Alan Cox0d88a102006-01-18 17:44:10 -0800192 if (!mci)
193 return -ENOMEM;
194
Dave Peterson537fba22006-03-26 01:38:40 -0800195 debugf3("%s(): init mci\n", __func__);
Doug Thompson37f04582006-06-30 01:56:07 -0700196 mci->dev = &pdev->dev;
Alan Cox0d88a102006-01-18 17:44:10 -0800197 mci->mtype_cap = MEM_FLAG_DDR;
Alan Cox0d88a102006-01-18 17:44:10 -0800198 mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
199 /* I"m not sure about this but I think that all RDRAM is SECDED */
200 mci->edac_cap = EDAC_FLAG_SECDED;
Dave Peterson680cbbb2006-03-26 01:38:41 -0800201 mci->mod_name = EDAC_MOD_STR;
Doug Thompson37f04582006-06-30 01:56:07 -0700202 mci->mod_ver = I82860_REVISION;
Alan Cox0d88a102006-01-18 17:44:10 -0800203 mci->ctl_name = i82860_devs[dev_idx].ctl_name;
Dave Jiangc4192702007-07-19 01:49:47 -0700204 mci->dev_name = pci_name(pdev);
Alan Cox0d88a102006-01-18 17:44:10 -0800205 mci->edac_check = i82860_check;
206 mci->ctl_page_to_phys = NULL;
Doug Thompson13189522006-06-30 01:56:08 -0700207 i82860_init_csrows(mci, pdev);
Dave Jiangb4e8b372007-07-19 01:50:04 -0700208 i82860_get_error_info(mci, &discard); /* clear counters */
Alan Cox0d88a102006-01-18 17:44:10 -0800209
Doug Thompson2d7bbb92006-06-30 01:56:08 -0700210 /* Here we assume that we will never see multiple instances of this
211 * type of memory controller. The ID is therefore hardcoded to 0.
212 */
Doug Thompsonb8f6f972007-07-19 01:50:26 -0700213 if (edac_mc_add_mc(mci)) {
Dave Peterson537fba22006-03-26 01:38:40 -0800214 debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
Doug Thompson13189522006-06-30 01:56:08 -0700215 goto fail;
Alan Cox0d88a102006-01-18 17:44:10 -0800216 }
Dave Petersone7ecd892006-03-26 01:38:52 -0800217
Dave Jiang456a2f92007-07-19 01:50:10 -0700218 /* allocating generic PCI control info */
219 i82860_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
220 if (!i82860_pci) {
221 printk(KERN_WARNING
222 "%s(): Unable to create PCI control\n",
223 __func__);
224 printk(KERN_WARNING
225 "%s(): PCI error report via EDAC not setup\n",
226 __func__);
227 }
228
Doug Thompson13189522006-06-30 01:56:08 -0700229 /* get this far and it's successful */
230 debugf3("%s(): success\n", __func__);
231
232 return 0;
233
Douglas Thompson052dfb42007-07-19 01:50:13 -0700234fail:
Doug Thompson13189522006-06-30 01:56:08 -0700235 edac_mc_free(mci);
236 return -ENODEV;
Alan Cox0d88a102006-01-18 17:44:10 -0800237}
238
239/* returns count (>= 0), or negative on error */
240static int __devinit i82860_init_one(struct pci_dev *pdev,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700241 const struct pci_device_id *ent)
Alan Cox0d88a102006-01-18 17:44:10 -0800242{
243 int rc;
244
Dave Peterson537fba22006-03-26 01:38:40 -0800245 debugf0("%s()\n", __func__);
Dave Peterson537fba22006-03-26 01:38:40 -0800246 i82860_printk(KERN_INFO, "i82860 init one\n");
Dave Petersone7ecd892006-03-26 01:38:52 -0800247
248 if (pci_enable_device(pdev) < 0)
Alan Cox0d88a102006-01-18 17:44:10 -0800249 return -EIO;
Dave Petersone7ecd892006-03-26 01:38:52 -0800250
Alan Cox0d88a102006-01-18 17:44:10 -0800251 rc = i82860_probe1(pdev, ent->driver_data);
Dave Petersone7ecd892006-03-26 01:38:52 -0800252
253 if (rc == 0)
Alan Cox0d88a102006-01-18 17:44:10 -0800254 mci_pdev = pci_dev_get(pdev);
Dave Petersone7ecd892006-03-26 01:38:52 -0800255
Alan Cox0d88a102006-01-18 17:44:10 -0800256 return rc;
257}
258
259static void __devexit i82860_remove_one(struct pci_dev *pdev)
260{
261 struct mem_ctl_info *mci;
262
Dave Peterson537fba22006-03-26 01:38:40 -0800263 debugf0("%s()\n", __func__);
Alan Cox0d88a102006-01-18 17:44:10 -0800264
Dave Jiang456a2f92007-07-19 01:50:10 -0700265 if (i82860_pci)
266 edac_pci_release_generic_ctl(i82860_pci);
267
Doug Thompson37f04582006-06-30 01:56:07 -0700268 if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
Dave Peterson18dbc332006-03-26 01:38:50 -0800269 return;
270
271 edac_mc_free(mci);
Alan Cox0d88a102006-01-18 17:44:10 -0800272}
273
274static const struct pci_device_id i82860_pci_tbl[] __devinitdata = {
Dave Petersone7ecd892006-03-26 01:38:52 -0800275 {
Dave Jiangb4e8b372007-07-19 01:50:04 -0700276 PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
277 I82860},
Dave Petersone7ecd892006-03-26 01:38:52 -0800278 {
Dave Jiangb4e8b372007-07-19 01:50:04 -0700279 0,
280 } /* 0 terminated list. */
Alan Cox0d88a102006-01-18 17:44:10 -0800281};
282
283MODULE_DEVICE_TABLE(pci, i82860_pci_tbl);
284
285static struct pci_driver i82860_driver = {
Dave Peterson680cbbb2006-03-26 01:38:41 -0800286 .name = EDAC_MOD_STR,
Alan Cox0d88a102006-01-18 17:44:10 -0800287 .probe = i82860_init_one,
288 .remove = __devexit_p(i82860_remove_one),
289 .id_table = i82860_pci_tbl,
290};
291
Alan Coxda9bb1d2006-01-18 17:44:13 -0800292static int __init i82860_init(void)
Alan Cox0d88a102006-01-18 17:44:10 -0800293{
294 int pci_rc;
295
Dave Peterson537fba22006-03-26 01:38:40 -0800296 debugf3("%s()\n", __func__);
Dave Petersone7ecd892006-03-26 01:38:52 -0800297
Hitoshi Mitakec3c52bc2008-04-29 01:03:18 -0700298 /* Ensure that the OPSTATE is set correctly for POLL or NMI */
299 opstate_init();
300
Alan Cox0d88a102006-01-18 17:44:10 -0800301 if ((pci_rc = pci_register_driver(&i82860_driver)) < 0)
Dave Petersone8a491b2006-03-26 01:38:43 -0800302 goto fail0;
Alan Cox0d88a102006-01-18 17:44:10 -0800303
304 if (!mci_pdev) {
Alan Cox0d88a102006-01-18 17:44:10 -0800305 mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
Douglas Thompson052dfb42007-07-19 01:50:13 -0700306 PCI_DEVICE_ID_INTEL_82860_0, NULL);
Dave Petersone7ecd892006-03-26 01:38:52 -0800307
Alan Cox0d88a102006-01-18 17:44:10 -0800308 if (mci_pdev == NULL) {
309 debugf0("860 pci_get_device fail\n");
Dave Petersone8a491b2006-03-26 01:38:43 -0800310 pci_rc = -ENODEV;
311 goto fail1;
Alan Cox0d88a102006-01-18 17:44:10 -0800312 }
Dave Petersone7ecd892006-03-26 01:38:52 -0800313
Alan Cox0d88a102006-01-18 17:44:10 -0800314 pci_rc = i82860_init_one(mci_pdev, i82860_pci_tbl);
Dave Petersone7ecd892006-03-26 01:38:52 -0800315
Alan Cox0d88a102006-01-18 17:44:10 -0800316 if (pci_rc < 0) {
317 debugf0("860 init fail\n");
Dave Petersone8a491b2006-03-26 01:38:43 -0800318 pci_rc = -ENODEV;
319 goto fail1;
Alan Cox0d88a102006-01-18 17:44:10 -0800320 }
321 }
Dave Petersone7ecd892006-03-26 01:38:52 -0800322
Alan Cox0d88a102006-01-18 17:44:10 -0800323 return 0;
Dave Petersone8a491b2006-03-26 01:38:43 -0800324
Douglas Thompson052dfb42007-07-19 01:50:13 -0700325fail1:
Dave Petersone8a491b2006-03-26 01:38:43 -0800326 pci_unregister_driver(&i82860_driver);
327
Douglas Thompson052dfb42007-07-19 01:50:13 -0700328fail0:
Dave Petersone8a491b2006-03-26 01:38:43 -0800329 if (mci_pdev != NULL)
330 pci_dev_put(mci_pdev);
331
332 return pci_rc;
Alan Cox0d88a102006-01-18 17:44:10 -0800333}
334
335static void __exit i82860_exit(void)
336{
Dave Peterson537fba22006-03-26 01:38:40 -0800337 debugf3("%s()\n", __func__);
Alan Cox0d88a102006-01-18 17:44:10 -0800338
339 pci_unregister_driver(&i82860_driver);
Dave Petersone8a491b2006-03-26 01:38:43 -0800340
341 if (mci_pdev != NULL)
Alan Cox0d88a102006-01-18 17:44:10 -0800342 pci_dev_put(mci_pdev);
Alan Cox0d88a102006-01-18 17:44:10 -0800343}
344
345module_init(i82860_init);
346module_exit(i82860_exit);
347
348MODULE_LICENSE("GPL");
Dave Petersone7ecd892006-03-26 01:38:52 -0800349MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com) "
Douglas Thompson052dfb42007-07-19 01:50:13 -0700350 "Ben Woodard <woodard@redhat.com>");
Alan Cox0d88a102006-01-18 17:44:10 -0800351MODULE_DESCRIPTION("ECC support for Intel 82860 memory hub controllers");
Hitoshi Mitakec3c52bc2008-04-29 01:03:18 -0700352
353module_param(edac_op_state, int, 0444);
354MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");