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.
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)
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>
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 */
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
38 struct i82860_dev_info {
42 struct i82860_error_info {
49 static const struct i82860_dev_info i82860_devs[] = {
51 .ctl_name = "i82860"},
54 static struct pci_dev *mci_pdev = NULL; /* init dev: in case that AGP code
55 has already registered driver */
57 static int i82860_registered = 1;
59 static void i82860_get_error_info (struct mem_ctl_info *mci,
60 struct i82860_error_info *info)
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
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);
72 pci_write_bits16(mci->pdev, I82860_ERRSTS, 0x0003, 0x0003);
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.
79 if (!(info->errsts2 & 0x0003))
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,
88 static int i82860_process_error_info (struct mem_ctl_info *mci,
89 struct i82860_error_info *info, int handle_errors)
93 if (!(info->errsts2 & 0x0003))
99 if ((info->errsts ^ info->errsts2) & 0x0003) {
100 edac_mc_handle_ce_no_info(mci, "UE overwrote CE");
101 info->errsts = info->errsts2;
104 info->eap >>= PAGE_SHIFT;
105 row = edac_mc_find_csrow_by_page(mci, info->eap);
107 if (info->errsts & 0x0002)
108 edac_mc_handle_ue(mci, info->eap, 0, row, "i82860 UE");
110 edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row,
116 static void i82860_check(struct mem_ctl_info *mci)
118 struct i82860_error_info info;
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);
125 static int i82860_probe1(struct pci_dev *pdev, int dev_idx)
129 struct mem_ctl_info *mci = NULL;
130 unsigned long last_cumul_size;
132 u16 mchcfg_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */
134 /* RDRAM has channels but these don't map onto the abstractions that
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.
142 mci = edac_mc_alloc(0, 16, 1);
146 debugf3("MC: " __FILE__ ": %s(): init mci\n", __func__);
149 mci->mtype_cap = MEM_FLAG_DDR;
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;
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;
163 pci_read_config_word(mci->pdev, I82860_MCHCFG, &mchcfg_ddim);
164 mchcfg_ddim = mchcfg_ddim & 0x180;
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
172 for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) {
175 struct csrow_info *csrow = &mci->csrows[index];
177 pci_read_config_word(mci->pdev, I82860_GBA + index * 2,
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 */
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;
198 pci_write_bits16(mci->pdev, I82860_ERRSTS, 0x0003, 0x0003);
200 if (edac_mc_add_mc(mci)) {
201 debugf3("MC: " __FILE__
202 ": %s(): failed edac_mc_add_mc()\n",
206 /* get this far and it's successful */
207 debugf3("MC: " __FILE__ ": %s(): success\n", __func__);
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)
219 debugf0("MC: " __FILE__ ": %s()\n", __func__);
221 printk(KERN_INFO "i82860 init one\n");
222 if(pci_enable_device(pdev) < 0)
224 rc = i82860_probe1(pdev, ent->driver_data);
226 mci_pdev = pci_dev_get(pdev);
230 static void __devexit i82860_remove_one(struct pci_dev *pdev)
232 struct mem_ctl_info *mci;
234 debugf0(__FILE__ ": %s()\n", __func__);
236 mci = edac_mc_find_mci_by_pdev(pdev);
237 if ((mci != NULL) && (edac_mc_del_mc(mci) == 0))
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,
244 {0,} /* 0 terminated list. */
247 MODULE_DEVICE_TABLE(pci, i82860_pci_tbl);
249 static struct pci_driver i82860_driver = {
251 .probe = i82860_init_one,
252 .remove = __devexit_p(i82860_remove_one),
253 .id_table = i82860_pci_tbl,
256 static int __init i82860_init(void)
260 debugf3("MC: " __FILE__ ": %s()\n", __func__);
261 if ((pci_rc = pci_register_driver(&i82860_driver)) < 0)
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");
272 pci_rc = i82860_init_one(mci_pdev, i82860_pci_tbl);
274 debugf0("860 init fail\n");
275 pci_dev_put(mci_pdev);
282 static void __exit i82860_exit(void)
284 debugf3("MC: " __FILE__ ": %s()\n", __func__);
286 pci_unregister_driver(&i82860_driver);
287 if (!i82860_registered) {
288 i82860_remove_one(mci_pdev);
289 pci_dev_put(mci_pdev);
293 module_init(i82860_init);
294 module_exit(i82860_exit);
296 MODULE_LICENSE("GPL");
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");