Blame view
drivers/edac/i82860_edac.c
8.65 KB
0d88a10e5 [PATCH] EDAC: dri... |
1 2 3 4 5 6 7 8 9 10 |
/* * Intel 82860 Memory Controller kernel module * (C) 2005 Red Hat (http://www.redhat.com) * This file may be distributed under the terms of the * GNU General Public License. * * Written by Ben Woodard <woodard@redhat.com> * shamelessly copied from and based upon the edac_i82875 driver * by Thayne Harbaugh of Linux Networx. (http://lnxi.com) */ |
0d88a10e5 [PATCH] EDAC: dri... |
11 12 13 14 |
#include <linux/module.h> #include <linux/init.h> #include <linux/pci.h> #include <linux/pci_ids.h> |
c3c52bce6 edac: fix module ... |
15 |
#include <linux/edac.h> |
20bcb7a81 drivers/edac: mod... |
16 |
#include "edac_core.h" |
0d88a10e5 [PATCH] EDAC: dri... |
17 |
|
152ba3942 edac: Drop __DATE... |
18 |
#define I82860_REVISION " Ver: 2.0.2" |
929a40ec3 [PATCH] EDAC: fix... |
19 |
#define EDAC_MOD_STR "i82860_edac" |
37f04581a [PATCH] EDAC: PCI... |
20 |
|
537fba289 [PATCH] EDAC: pri... |
21 |
#define i82860_printk(level, fmt, arg...) \ |
e7ecd8910 [PATCH] EDAC: for... |
22 |
edac_printk(level, "i82860", fmt, ##arg) |
537fba289 [PATCH] EDAC: pri... |
23 24 |
#define i82860_mc_printk(mci, level, fmt, arg...) \ |
e7ecd8910 [PATCH] EDAC: for... |
25 |
edac_mc_chipset_printk(mci, level, "i82860", fmt, ##arg) |
537fba289 [PATCH] EDAC: pri... |
26 |
|
0d88a10e5 [PATCH] EDAC: dri... |
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
#ifndef PCI_DEVICE_ID_INTEL_82860_0 #define PCI_DEVICE_ID_INTEL_82860_0 0x2531 #endif /* PCI_DEVICE_ID_INTEL_82860_0 */ #define I82860_MCHCFG 0x50 #define I82860_GBA 0x60 #define I82860_GBA_MASK 0x7FF #define I82860_GBA_SHIFT 24 #define I82860_ERRSTS 0xC8 #define I82860_EAP 0xE4 #define I82860_DERRCTL_STS 0xE2 enum i82860_chips { I82860 = 0, }; struct i82860_dev_info { const char *ctl_name; }; struct i82860_error_info { u16 errsts; u32 eap; u16 derrsyn; u16 errsts2; }; static const struct i82860_dev_info i82860_devs[] = { [I82860] = { |
052dfb45c drivers/edac: cle... |
56 |
.ctl_name = "i82860"}, |
0d88a10e5 [PATCH] EDAC: dri... |
57 |
}; |
f044091ca drivers/edac: rem... |
58 |
static struct pci_dev *mci_pdev; /* init dev: in case that AGP code |
e7ecd8910 [PATCH] EDAC: for... |
59 60 |
* has already registered driver */ |
456a2f955 drivers/edac: dri... |
61 |
static struct edac_pci_ctl_info *i82860_pci; |
0d88a10e5 [PATCH] EDAC: dri... |
62 |
|
e7ecd8910 [PATCH] EDAC: for... |
63 |
static void i82860_get_error_info(struct mem_ctl_info *mci, |
052dfb45c drivers/edac: cle... |
64 |
struct i82860_error_info *info) |
0d88a10e5 [PATCH] EDAC: dri... |
65 |
{ |
37f04581a [PATCH] EDAC: PCI... |
66 67 68 |
struct pci_dev *pdev; pdev = to_pci_dev(mci->dev); |
0d88a10e5 [PATCH] EDAC: dri... |
69 70 71 72 73 |
/* * This is a mess because there is no atomic way to read all the * registers at once and the registers can transition from CE being * overwritten by UE. */ |
37f04581a [PATCH] EDAC: PCI... |
74 75 76 77 |
pci_read_config_word(pdev, I82860_ERRSTS, &info->errsts); pci_read_config_dword(pdev, I82860_EAP, &info->eap); pci_read_config_word(pdev, I82860_DERRCTL_STS, &info->derrsyn); pci_read_config_word(pdev, I82860_ERRSTS, &info->errsts2); |
0d88a10e5 [PATCH] EDAC: dri... |
78 |
|
37f04581a [PATCH] EDAC: PCI... |
79 |
pci_write_bits16(pdev, I82860_ERRSTS, 0x0003, 0x0003); |
0d88a10e5 [PATCH] EDAC: dri... |
80 81 82 83 84 85 86 87 |
/* * If the error is the same for both reads then the first set of reads * is valid. If there is a change then there is a CE no info and the * second set of reads is valid and should be UE info. */ if (!(info->errsts2 & 0x0003)) return; |
e7ecd8910 [PATCH] EDAC: for... |
88 |
|
0d88a10e5 [PATCH] EDAC: dri... |
89 |
if ((info->errsts ^ info->errsts2) & 0x0003) { |
37f04581a [PATCH] EDAC: PCI... |
90 |
pci_read_config_dword(pdev, I82860_EAP, &info->eap); |
b4e8b3720 drivers/edac: Lin... |
91 |
pci_read_config_word(pdev, I82860_DERRCTL_STS, &info->derrsyn); |
0d88a10e5 [PATCH] EDAC: dri... |
92 93 |
} } |
e7ecd8910 [PATCH] EDAC: for... |
94 |
static int i82860_process_error_info(struct mem_ctl_info *mci, |
052dfb45c drivers/edac: cle... |
95 96 |
struct i82860_error_info *info, int handle_errors) |
0d88a10e5 [PATCH] EDAC: dri... |
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
{ int row; if (!(info->errsts2 & 0x0003)) return 0; if (!handle_errors) return 1; if ((info->errsts ^ info->errsts2) & 0x0003) { edac_mc_handle_ce_no_info(mci, "UE overwrote CE"); info->errsts = info->errsts2; } info->eap >>= PAGE_SHIFT; row = edac_mc_find_csrow_by_page(mci, info->eap); if (info->errsts & 0x0002) edac_mc_handle_ue(mci, info->eap, 0, row, "i82860 UE"); else |
e7ecd8910 [PATCH] EDAC: for... |
117 |
edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row, 0, |
052dfb45c drivers/edac: cle... |
118 |
"i82860 UE"); |
0d88a10e5 [PATCH] EDAC: dri... |
119 120 121 122 123 124 125 |
return 1; } static void i82860_check(struct mem_ctl_info *mci) { struct i82860_error_info info; |
537fba289 [PATCH] EDAC: pri... |
126 127 |
debugf1("MC%d: %s() ", mci->mc_idx, __func__); |
0d88a10e5 [PATCH] EDAC: dri... |
128 129 130 |
i82860_get_error_info(mci, &info); i82860_process_error_info(mci, &info, 1); } |
131895251 [PATCH] EDAC: pro... |
131 |
static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev) |
0d88a10e5 [PATCH] EDAC: dri... |
132 |
{ |
0d88a10e5 [PATCH] EDAC: dri... |
133 |
unsigned long last_cumul_size; |
b4e8b3720 drivers/edac: Lin... |
134 |
u16 mchcfg_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */ |
131895251 [PATCH] EDAC: pro... |
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
u16 value; u32 cumul_size; struct csrow_info *csrow; int index; pci_read_config_word(pdev, I82860_MCHCFG, &mchcfg_ddim); mchcfg_ddim = mchcfg_ddim & 0x180; last_cumul_size = 0; /* The group row boundary (GRA) reg values are boundary address * for each DRAM row with a granularity of 16MB. GRA regs are * cumulative; therefore GRA15 will contain the total memory contained * in all eight rows. */ for (index = 0; index < mci->nr_csrows; index++) { csrow = &mci->csrows[index]; pci_read_config_word(pdev, I82860_GBA + index * 2, &value); cumul_size = (value & I82860_GBA_MASK) << |
052dfb45c drivers/edac: cle... |
153 |
(I82860_GBA_SHIFT - PAGE_SHIFT); |
131895251 [PATCH] EDAC: pro... |
154 155 156 |
debugf3("%s(): (%d) cumul_size 0x%x ", __func__, index, cumul_size); |
0d88a10e5 [PATCH] EDAC: dri... |
157 |
|
131895251 [PATCH] EDAC: pro... |
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
if (cumul_size == last_cumul_size) continue; /* not populated */ csrow->first_page = last_cumul_size; csrow->last_page = cumul_size - 1; csrow->nr_pages = cumul_size - last_cumul_size; last_cumul_size = cumul_size; csrow->grain = 1 << 12; /* I82860_EAP has 4KiB reolution */ csrow->mtype = MEM_RMBS; csrow->dtype = DEV_UNKNOWN; csrow->edac_mode = mchcfg_ddim ? EDAC_SECDED : EDAC_NONE; } } static int i82860_probe1(struct pci_dev *pdev, int dev_idx) { struct mem_ctl_info *mci; struct i82860_error_info discard; |
0d88a10e5 [PATCH] EDAC: dri... |
176 177 178 179 180 181 182 183 184 |
/* RDRAM has channels but these don't map onto the abstractions that edac uses. The device groups from the GRA registers seem to map reasonably well onto the notion of a chip select row. There are 16 GRA registers and since the name is associated with the channel and the GRA registers map to physical devices so we are going to make 1 channel for group. */ |
b8f6f9755 drivers/edac: fix... |
185 |
mci = edac_mc_alloc(0, 16, 1, 0); |
e7ecd8910 [PATCH] EDAC: for... |
186 |
|
0d88a10e5 [PATCH] EDAC: dri... |
187 188 |
if (!mci) return -ENOMEM; |
537fba289 [PATCH] EDAC: pri... |
189 190 |
debugf3("%s(): init mci ", __func__); |
37f04581a [PATCH] EDAC: PCI... |
191 |
mci->dev = &pdev->dev; |
0d88a10e5 [PATCH] EDAC: dri... |
192 |
mci->mtype_cap = MEM_FLAG_DDR; |
0d88a10e5 [PATCH] EDAC: dri... |
193 194 195 |
mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; /* I"m not sure about this but I think that all RDRAM is SECDED */ mci->edac_cap = EDAC_FLAG_SECDED; |
680cbbbb0 [PATCH] EDAC: nam... |
196 |
mci->mod_name = EDAC_MOD_STR; |
37f04581a [PATCH] EDAC: PCI... |
197 |
mci->mod_ver = I82860_REVISION; |
0d88a10e5 [PATCH] EDAC: dri... |
198 |
mci->ctl_name = i82860_devs[dev_idx].ctl_name; |
c4192705f drivers/edac: add... |
199 |
mci->dev_name = pci_name(pdev); |
0d88a10e5 [PATCH] EDAC: dri... |
200 201 |
mci->edac_check = i82860_check; mci->ctl_page_to_phys = NULL; |
131895251 [PATCH] EDAC: pro... |
202 |
i82860_init_csrows(mci, pdev); |
b4e8b3720 drivers/edac: Lin... |
203 |
i82860_get_error_info(mci, &discard); /* clear counters */ |
0d88a10e5 [PATCH] EDAC: dri... |
204 |
|
2d7bbb91c [PATCH] EDAC: mc ... |
205 206 207 |
/* Here we assume that we will never see multiple instances of this * type of memory controller. The ID is therefore hardcoded to 0. */ |
b8f6f9755 drivers/edac: fix... |
208 |
if (edac_mc_add_mc(mci)) { |
537fba289 [PATCH] EDAC: pri... |
209 210 |
debugf3("%s(): failed edac_mc_add_mc() ", __func__); |
131895251 [PATCH] EDAC: pro... |
211 |
goto fail; |
0d88a10e5 [PATCH] EDAC: dri... |
212 |
} |
e7ecd8910 [PATCH] EDAC: for... |
213 |
|
456a2f955 drivers/edac: dri... |
214 215 216 217 218 219 220 221 222 223 224 225 |
/* allocating generic PCI control info */ i82860_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); if (!i82860_pci) { printk(KERN_WARNING "%s(): Unable to create PCI control ", __func__); printk(KERN_WARNING "%s(): PCI error report via EDAC not setup ", __func__); } |
131895251 [PATCH] EDAC: pro... |
226 227 228 229 230 |
/* get this far and it's successful */ debugf3("%s(): success ", __func__); return 0; |
052dfb45c drivers/edac: cle... |
231 |
fail: |
131895251 [PATCH] EDAC: pro... |
232 233 |
edac_mc_free(mci); return -ENODEV; |
0d88a10e5 [PATCH] EDAC: dri... |
234 235 236 237 |
} /* returns count (>= 0), or negative on error */ static int __devinit i82860_init_one(struct pci_dev *pdev, |
052dfb45c drivers/edac: cle... |
238 |
const struct pci_device_id *ent) |
0d88a10e5 [PATCH] EDAC: dri... |
239 240 |
{ int rc; |
537fba289 [PATCH] EDAC: pri... |
241 242 |
debugf0("%s() ", __func__); |
537fba289 [PATCH] EDAC: pri... |
243 244 |
i82860_printk(KERN_INFO, "i82860 init one "); |
e7ecd8910 [PATCH] EDAC: for... |
245 246 |
if (pci_enable_device(pdev) < 0) |
0d88a10e5 [PATCH] EDAC: dri... |
247 |
return -EIO; |
e7ecd8910 [PATCH] EDAC: for... |
248 |
|
0d88a10e5 [PATCH] EDAC: dri... |
249 |
rc = i82860_probe1(pdev, ent->driver_data); |
e7ecd8910 [PATCH] EDAC: for... |
250 251 |
if (rc == 0) |
0d88a10e5 [PATCH] EDAC: dri... |
252 |
mci_pdev = pci_dev_get(pdev); |
e7ecd8910 [PATCH] EDAC: for... |
253 |
|
0d88a10e5 [PATCH] EDAC: dri... |
254 255 256 257 258 259 |
return rc; } static void __devexit i82860_remove_one(struct pci_dev *pdev) { struct mem_ctl_info *mci; |
537fba289 [PATCH] EDAC: pri... |
260 261 |
debugf0("%s() ", __func__); |
0d88a10e5 [PATCH] EDAC: dri... |
262 |
|
456a2f955 drivers/edac: dri... |
263 264 |
if (i82860_pci) edac_pci_release_generic_ctl(i82860_pci); |
37f04581a [PATCH] EDAC: PCI... |
265 |
if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) |
18dbc337a [PATCH] EDAC: pro... |
266 267 268 |
return; edac_mc_free(mci); |
0d88a10e5 [PATCH] EDAC: dri... |
269 270 271 |
} static const struct pci_device_id i82860_pci_tbl[] __devinitdata = { |
e7ecd8910 [PATCH] EDAC: for... |
272 |
{ |
b4e8b3720 drivers/edac: Lin... |
273 274 |
PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, I82860}, |
e7ecd8910 [PATCH] EDAC: for... |
275 |
{ |
b4e8b3720 drivers/edac: Lin... |
276 277 |
0, } /* 0 terminated list. */ |
0d88a10e5 [PATCH] EDAC: dri... |
278 279 280 281 282 |
}; MODULE_DEVICE_TABLE(pci, i82860_pci_tbl); static struct pci_driver i82860_driver = { |
680cbbbb0 [PATCH] EDAC: nam... |
283 |
.name = EDAC_MOD_STR, |
0d88a10e5 [PATCH] EDAC: dri... |
284 285 286 287 |
.probe = i82860_init_one, .remove = __devexit_p(i82860_remove_one), .id_table = i82860_pci_tbl, }; |
da9bb1d27 [PATCH] EDAC: cor... |
288 |
static int __init i82860_init(void) |
0d88a10e5 [PATCH] EDAC: dri... |
289 290 |
{ int pci_rc; |
537fba289 [PATCH] EDAC: pri... |
291 292 |
debugf3("%s() ", __func__); |
e7ecd8910 [PATCH] EDAC: for... |
293 |
|
c3c52bce6 edac: fix module ... |
294 295 |
/* Ensure that the OPSTATE is set correctly for POLL or NMI */ opstate_init(); |
0d88a10e5 [PATCH] EDAC: dri... |
296 |
if ((pci_rc = pci_register_driver(&i82860_driver)) < 0) |
e8a491b40 [PATCH] EDAC: i82... |
297 |
goto fail0; |
0d88a10e5 [PATCH] EDAC: dri... |
298 299 |
if (!mci_pdev) { |
0d88a10e5 [PATCH] EDAC: dri... |
300 |
mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL, |
052dfb45c drivers/edac: cle... |
301 |
PCI_DEVICE_ID_INTEL_82860_0, NULL); |
e7ecd8910 [PATCH] EDAC: for... |
302 |
|
0d88a10e5 [PATCH] EDAC: dri... |
303 304 305 |
if (mci_pdev == NULL) { debugf0("860 pci_get_device fail "); |
e8a491b40 [PATCH] EDAC: i82... |
306 307 |
pci_rc = -ENODEV; goto fail1; |
0d88a10e5 [PATCH] EDAC: dri... |
308 |
} |
e7ecd8910 [PATCH] EDAC: for... |
309 |
|
0d88a10e5 [PATCH] EDAC: dri... |
310 |
pci_rc = i82860_init_one(mci_pdev, i82860_pci_tbl); |
e7ecd8910 [PATCH] EDAC: for... |
311 |
|
0d88a10e5 [PATCH] EDAC: dri... |
312 313 314 |
if (pci_rc < 0) { debugf0("860 init fail "); |
e8a491b40 [PATCH] EDAC: i82... |
315 316 |
pci_rc = -ENODEV; goto fail1; |
0d88a10e5 [PATCH] EDAC: dri... |
317 318 |
} } |
e7ecd8910 [PATCH] EDAC: for... |
319 |
|
0d88a10e5 [PATCH] EDAC: dri... |
320 |
return 0; |
e8a491b40 [PATCH] EDAC: i82... |
321 |
|
052dfb45c drivers/edac: cle... |
322 |
fail1: |
e8a491b40 [PATCH] EDAC: i82... |
323 |
pci_unregister_driver(&i82860_driver); |
052dfb45c drivers/edac: cle... |
324 |
fail0: |
e8a491b40 [PATCH] EDAC: i82... |
325 326 327 328 |
if (mci_pdev != NULL) pci_dev_put(mci_pdev); return pci_rc; |
0d88a10e5 [PATCH] EDAC: dri... |
329 330 331 332 |
} static void __exit i82860_exit(void) { |
537fba289 [PATCH] EDAC: pri... |
333 334 |
debugf3("%s() ", __func__); |
0d88a10e5 [PATCH] EDAC: dri... |
335 336 |
pci_unregister_driver(&i82860_driver); |
e8a491b40 [PATCH] EDAC: i82... |
337 338 |
if (mci_pdev != NULL) |
0d88a10e5 [PATCH] EDAC: dri... |
339 |
pci_dev_put(mci_pdev); |
0d88a10e5 [PATCH] EDAC: dri... |
340 341 342 343 344 345 |
} module_init(i82860_init); module_exit(i82860_exit); MODULE_LICENSE("GPL"); |
e7ecd8910 [PATCH] EDAC: for... |
346 |
MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com) " |
052dfb45c drivers/edac: cle... |
347 |
"Ben Woodard <woodard@redhat.com>"); |
0d88a10e5 [PATCH] EDAC: dri... |
348 |
MODULE_DESCRIPTION("ECC support for Intel 82860 memory hub controllers"); |
c3c52bce6 edac: fix module ... |
349 350 351 |
module_param(edac_op_state, int, 0444); MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); |