Blame view
drivers/edac/r82600_edac.c
11.6 KB
2f768af73 [PATCH] EDAC: dri... |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* * Radisys 82600 Embedded chipset Memory Controller kernel module * (C) 2005 EADS Astrium * This file may be distributed under the terms of the * GNU General Public License. * * Written by Tim Small <tim@buttersideup.com>, based on work by Thayne * Harbaugh, Dan Hollis <goemon at anime dot net> and others. * * $Id: edac_r82600.c,v 1.1.2.6 2005/10/05 00:43:44 dsp_llnl Exp $ * * Written with reference to 82600 High Integration Dual PCI System * Controller Data Book: |
c4192705f drivers/edac: add... |
14 |
* www.radisys.com/files/support_downloads/007-01277-0002.82600DataBook.pdf |
2f768af73 [PATCH] EDAC: dri... |
15 16 |
* references to this document given in [] */ |
2f768af73 [PATCH] EDAC: dri... |
17 18 |
#include <linux/module.h> #include <linux/init.h> |
2f768af73 [PATCH] EDAC: dri... |
19 20 |
#include <linux/pci.h> #include <linux/pci_ids.h> |
c3c52bce6 edac: fix module ... |
21 |
#include <linux/edac.h> |
20bcb7a81 drivers/edac: mod... |
22 |
#include "edac_core.h" |
2f768af73 [PATCH] EDAC: dri... |
23 |
|
152ba3942 edac: Drop __DATE... |
24 |
#define R82600_REVISION " Ver: 2.0.2" |
929a40ec3 [PATCH] EDAC: fix... |
25 |
#define EDAC_MOD_STR "r82600_edac" |
37f04581a [PATCH] EDAC: PCI... |
26 |
|
537fba289 [PATCH] EDAC: pri... |
27 |
#define r82600_printk(level, fmt, arg...) \ |
e7ecd8910 [PATCH] EDAC: for... |
28 |
edac_printk(level, "r82600", fmt, ##arg) |
537fba289 [PATCH] EDAC: pri... |
29 30 |
#define r82600_mc_printk(mci, level, fmt, arg...) \ |
e7ecd8910 [PATCH] EDAC: for... |
31 |
edac_mc_chipset_printk(mci, level, "r82600", fmt, ##arg) |
537fba289 [PATCH] EDAC: pri... |
32 |
|
2f768af73 [PATCH] EDAC: dri... |
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
/* Radisys say "The 82600 integrates a main memory SDRAM controller that * supports up to four banks of memory. The four banks can support a mix of * sizes of 64 bit wide (72 bits with ECC) Synchronous DRAM (SDRAM) DIMMs, * each of which can be any size from 16MB to 512MB. Both registered (control * signals buffered) and unbuffered DIMM types are supported. Mixing of * registered and unbuffered DIMMs as well as mixing of ECC and non-ECC DIMMs * is not allowed. The 82600 SDRAM interface operates at the same frequency as * the CPU bus, 66MHz, 100MHz or 133MHz." */ #define R82600_NR_CSROWS 4 #define R82600_NR_CHANS 1 #define R82600_NR_DIMMS 4 #define R82600_BRIDGE_ID 0x8200 /* Radisys 82600 register addresses - device 0 function 0 - PCI bridge */ #define R82600_DRAMC 0x57 /* Various SDRAM related control bits * all bits are R/W * * 7 SDRAM ISA Hole Enable * 6 Flash Page Mode Enable * 5 ECC Enable: 1=ECC 0=noECC * 4 DRAM DIMM Type: 1= * 3 BIOS Alias Disable * 2 SDRAM BIOS Flash Write Enable * 1:0 SDRAM Refresh Rate: 00=Disabled * 01=7.8usec (256Mbit SDRAMs) * 10=15.6us 11=125usec */ #define R82600_SDRAMC 0x76 /* "SDRAM Control Register" * More SDRAM related control bits * all bits are R/W * * 15:8 Reserved. * * 7:5 Special SDRAM Mode Select * * 4 Force ECC * * 1=Drive ECC bits to 0 during * write cycles (i.e. ECC test mode) * * 0=Normal ECC functioning * * 3 Enhanced Paging Enable * * 2 CAS# Latency 0=3clks 1=2clks * * 1 RAS# to CAS# Delay 0=3 1=2 * * 0 RAS# Precharge 0=3 1=2 */ #define R82600_EAP 0x80 /* ECC Error Address Pointer Register * * 31 Disable Hardware Scrubbing (RW) * 0=Scrub on corrected read * 1=Don't scrub on corrected read * * 30:12 Error Address Pointer (RO) * Upper 19 bits of error address * * 11:4 Syndrome Bits (RO) * * 3 BSERR# on multibit error (RW) * 1=enable 0=disable * * 2 NMI on Single Bit Eror (RW) * 1=NMI triggered by SBE n.b. other * prerequeists * 0=NMI not triggered * * 1 MBE (R/WC) * read 1=MBE at EAP (see above) * read 0=no MBE, or SBE occurred first * write 1=Clear MBE status (must also * clear SBE) * write 0=NOP * * 1 SBE (R/WC) * read 1=SBE at EAP (see above) * read 0=no SBE, or MBE occurred first * write 1=Clear SBE status (must also * clear MBE) * write 0=NOP */ |
25985edce Fix common misspe... |
121 |
#define R82600_DRBA 0x60 /* + 0x60..0x63 SDRAM Row Boundary Address |
2f768af73 [PATCH] EDAC: dri... |
122 123 124 125 126 127 128 129 130 |
* Registers * * 7:0 Address lines 30:24 - upper limit of * each row [p57] */ struct r82600_error_info { u32 eapr; }; |
f044091ca drivers/edac: rem... |
131 |
static unsigned int disable_hardware_scrub; |
2f768af73 [PATCH] EDAC: dri... |
132 |
|
456a2f955 drivers/edac: dri... |
133 |
static struct edac_pci_ctl_info *r82600_pci; |
cddbfcacf drivers/edac: Lin... |
134 |
static void r82600_get_error_info(struct mem_ctl_info *mci, |
052dfb45c drivers/edac: cle... |
135 |
struct r82600_error_info *info) |
2f768af73 [PATCH] EDAC: dri... |
136 |
{ |
37f04581a [PATCH] EDAC: PCI... |
137 138 139 140 |
struct pci_dev *pdev; pdev = to_pci_dev(mci->dev); pci_read_config_dword(pdev, R82600_EAP, &info->eapr); |
2f768af73 [PATCH] EDAC: dri... |
141 142 143 |
if (info->eapr & BIT(0)) /* Clear error to allow next error to be reported [p.62] */ |
37f04581a [PATCH] EDAC: PCI... |
144 |
pci_write_bits32(pdev, R82600_EAP, |
cddbfcacf drivers/edac: Lin... |
145 146 |
((u32) BIT(0) & (u32) BIT(1)), ((u32) BIT(0) & (u32) BIT(1))); |
2f768af73 [PATCH] EDAC: dri... |
147 148 149 |
if (info->eapr & BIT(1)) /* Clear error to allow next error to be reported [p.62] */ |
37f04581a [PATCH] EDAC: PCI... |
150 |
pci_write_bits32(pdev, R82600_EAP, |
cddbfcacf drivers/edac: Lin... |
151 152 |
((u32) BIT(0) & (u32) BIT(1)), ((u32) BIT(0) & (u32) BIT(1))); |
2f768af73 [PATCH] EDAC: dri... |
153 |
} |
cddbfcacf drivers/edac: Lin... |
154 |
static int r82600_process_error_info(struct mem_ctl_info *mci, |
052dfb45c drivers/edac: cle... |
155 156 |
struct r82600_error_info *info, int handle_errors) |
2f768af73 [PATCH] EDAC: dri... |
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
{ int error_found; u32 eapaddr, page; u32 syndrome; error_found = 0; /* bits 30:12 store the upper 19 bits of the 32 bit error address */ eapaddr = ((info->eapr >> 12) & 0x7FFF) << 13; /* Syndrome in bits 11:4 [p.62] */ syndrome = (info->eapr >> 4) & 0xFF; /* the R82600 reports at less than page * * granularity (upper 19 bits only) */ page = eapaddr >> PAGE_SHIFT; |
cddbfcacf drivers/edac: Lin... |
172 |
if (info->eapr & BIT(0)) { /* CE? */ |
2f768af73 [PATCH] EDAC: dri... |
173 174 175 |
error_found = 1; if (handle_errors) |
cddbfcacf drivers/edac: Lin... |
176 |
edac_mc_handle_ce(mci, page, 0, /* not avail */ |
052dfb45c drivers/edac: cle... |
177 178 179 |
syndrome, edac_mc_find_csrow_by_page(mci, page), 0, mci->ctl_name); |
2f768af73 [PATCH] EDAC: dri... |
180 |
} |
cddbfcacf drivers/edac: Lin... |
181 |
if (info->eapr & BIT(1)) { /* UE? */ |
2f768af73 [PATCH] EDAC: dri... |
182 183 184 185 186 |
error_found = 1; if (handle_errors) /* 82600 doesn't give enough info */ edac_mc_handle_ue(mci, page, 0, |
052dfb45c drivers/edac: cle... |
187 188 |
edac_mc_find_csrow_by_page(mci, page), mci->ctl_name); |
2f768af73 [PATCH] EDAC: dri... |
189 190 191 192 193 194 195 196 |
} return error_found; } static void r82600_check(struct mem_ctl_info *mci) { struct r82600_error_info info; |
537fba289 [PATCH] EDAC: pri... |
197 198 |
debugf1("MC%d: %s() ", mci->mc_idx, __func__); |
2f768af73 [PATCH] EDAC: dri... |
199 200 201 |
r82600_get_error_info(mci, &info); r82600_process_error_info(mci, &info, 1); } |
131895251 [PATCH] EDAC: pro... |
202 |
static inline int ecc_enabled(u8 dramcr) |
2f768af73 [PATCH] EDAC: dri... |
203 |
{ |
131895251 [PATCH] EDAC: pro... |
204 205 206 207 |
return dramcr & BIT(5); } static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, |
052dfb45c drivers/edac: cle... |
208 |
u8 dramcr) |
131895251 [PATCH] EDAC: pro... |
209 210 |
{ struct csrow_info *csrow; |
2f768af73 [PATCH] EDAC: dri... |
211 |
int index; |
25985edce Fix common misspe... |
212 |
u8 drbar; /* SDRAM Row Boundary Address Register */ |
131895251 [PATCH] EDAC: pro... |
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
u32 row_high_limit, row_high_limit_last; u32 reg_sdram, ecc_on, row_base; ecc_on = ecc_enabled(dramcr); reg_sdram = dramcr & BIT(4); row_high_limit_last = 0; for (index = 0; index < mci->nr_csrows; index++) { csrow = &mci->csrows[index]; /* find the DRAM Chip Select Base address and mask */ pci_read_config_byte(pdev, R82600_DRBA + index, &drbar); debugf1("%s() Row=%d DRBA = %#0x ", __func__, index, drbar); row_high_limit = ((u32) drbar << 24); /* row_high_limit = ((u32)drbar << 24) | 0xffffffUL; */ |
25985edce Fix common misspe... |
231 232 |
debugf1("%s() Row=%d, Boundary Address=%#0x, Last = %#0x ", |
131895251 [PATCH] EDAC: pro... |
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 |
__func__, index, row_high_limit, row_high_limit_last); /* Empty row [p.57] */ if (row_high_limit == row_high_limit_last) continue; row_base = row_high_limit_last; csrow->first_page = row_base >> PAGE_SHIFT; csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1; csrow->nr_pages = csrow->last_page - csrow->first_page + 1; /* Error address is top 19 bits - so granularity is * * 14 bits */ csrow->grain = 1 << 14; csrow->mtype = reg_sdram ? MEM_RDDR : MEM_DDR; /* FIXME - check that this is unknowable with this chipset */ csrow->dtype = DEV_UNKNOWN; /* Mode is global on 82600 */ csrow->edac_mode = ecc_on ? EDAC_SECDED : EDAC_NONE; row_high_limit_last = row_high_limit; } } static int r82600_probe1(struct pci_dev *pdev, int dev_idx) { struct mem_ctl_info *mci; |
2f768af73 [PATCH] EDAC: dri... |
260 |
u8 dramcr; |
2f768af73 [PATCH] EDAC: dri... |
261 262 263 |
u32 eapr; u32 scrub_disabled; u32 sdram_refresh_rate; |
749ede574 [PATCH] EDAC: cle... |
264 |
struct r82600_error_info discard; |
2f768af73 [PATCH] EDAC: dri... |
265 |
|
537fba289 [PATCH] EDAC: pri... |
266 267 |
debugf0("%s() ", __func__); |
2f768af73 [PATCH] EDAC: dri... |
268 269 |
pci_read_config_byte(pdev, R82600_DRAMC, &dramcr); pci_read_config_dword(pdev, R82600_EAP, &eapr); |
2f768af73 [PATCH] EDAC: dri... |
270 271 |
scrub_disabled = eapr & BIT(31); sdram_refresh_rate = dramcr & (BIT(0) | BIT(1)); |
537fba289 [PATCH] EDAC: pri... |
272 273 274 |
debugf2("%s(): sdram refresh rate = %#0x ", __func__, sdram_refresh_rate); |
537fba289 [PATCH] EDAC: pri... |
275 276 |
debugf2("%s(): DRAMC register = %#0x ", __func__, dramcr); |
b8f6f9755 drivers/edac: fix... |
277 |
mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS, 0); |
2f768af73 [PATCH] EDAC: dri... |
278 |
|
131895251 [PATCH] EDAC: pro... |
279 280 |
if (mci == NULL) return -ENOMEM; |
2f768af73 [PATCH] EDAC: dri... |
281 |
|
537fba289 [PATCH] EDAC: pri... |
282 283 |
debugf0("%s(): mci = %p ", __func__, mci); |
37f04581a [PATCH] EDAC: PCI... |
284 |
mci->dev = &pdev->dev; |
2f768af73 [PATCH] EDAC: dri... |
285 |
mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR; |
2f768af73 [PATCH] EDAC: dri... |
286 |
mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; |
e7ecd8910 [PATCH] EDAC: for... |
287 288 289 |
/* FIXME try to work out if the chip leads have been used for COM2 * instead on this board? [MA6?] MAYBE: */ |
2f768af73 [PATCH] EDAC: dri... |
290 291 292 293 294 295 |
/* On the R82600, the pins for memory bits 72:65 - i.e. the * * EC bits are shared with the pins for COM2 (!), so if COM2 * * is enabled, we assume COM2 is wired up, and thus no EDAC * * is possible. */ mci->edac_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; |
e7ecd8910 [PATCH] EDAC: for... |
296 |
|
131895251 [PATCH] EDAC: pro... |
297 |
if (ecc_enabled(dramcr)) { |
2f768af73 [PATCH] EDAC: dri... |
298 |
if (scrub_disabled) |
537fba289 [PATCH] EDAC: pri... |
299 300 301 |
debugf3("%s(): mci = %p - Scrubbing disabled! EAP: " "%#0x ", __func__, mci, eapr); |
2f768af73 [PATCH] EDAC: dri... |
302 303 |
} else mci->edac_cap = EDAC_FLAG_NONE; |
680cbbbb0 [PATCH] EDAC: nam... |
304 |
mci->mod_name = EDAC_MOD_STR; |
37f04581a [PATCH] EDAC: PCI... |
305 |
mci->mod_ver = R82600_REVISION; |
2f768af73 [PATCH] EDAC: dri... |
306 |
mci->ctl_name = "R82600"; |
c4192705f drivers/edac: add... |
307 |
mci->dev_name = pci_name(pdev); |
2f768af73 [PATCH] EDAC: dri... |
308 309 |
mci->edac_check = r82600_check; mci->ctl_page_to_phys = NULL; |
131895251 [PATCH] EDAC: pro... |
310 |
r82600_init_csrows(mci, pdev, dramcr); |
cddbfcacf drivers/edac: Lin... |
311 |
r82600_get_error_info(mci, &discard); /* clear counters */ |
2f768af73 [PATCH] EDAC: dri... |
312 |
|
2d7bbb91c [PATCH] EDAC: mc ... |
313 314 315 |
/* 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... |
316 |
if (edac_mc_add_mc(mci)) { |
537fba289 [PATCH] EDAC: pri... |
317 318 |
debugf3("%s(): failed edac_mc_add_mc() ", __func__); |
2f768af73 [PATCH] EDAC: dri... |
319 320 321 322 |
goto fail; } /* get this far and it's successful */ |
2f768af73 [PATCH] EDAC: dri... |
323 |
if (disable_hardware_scrub) { |
537fba289 [PATCH] EDAC: pri... |
324 325 326 |
debugf3("%s(): Disabling Hardware Scrub (scrub on error) ", __func__); |
37f04581a [PATCH] EDAC: PCI... |
327 |
pci_write_bits32(pdev, R82600_EAP, BIT(31), BIT(31)); |
2f768af73 [PATCH] EDAC: dri... |
328 |
} |
456a2f955 drivers/edac: dri... |
329 330 331 332 333 334 335 336 337 338 339 340 |
/* allocating generic PCI control info */ r82600_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); if (!r82600_pci) { printk(KERN_WARNING "%s(): Unable to create PCI control ", __func__); printk(KERN_WARNING "%s(): PCI error report via EDAC not setup ", __func__); } |
537fba289 [PATCH] EDAC: pri... |
341 342 |
debugf3("%s(): success ", __func__); |
2f768af73 [PATCH] EDAC: dri... |
343 |
return 0; |
052dfb45c drivers/edac: cle... |
344 |
fail: |
131895251 [PATCH] EDAC: pro... |
345 346 |
edac_mc_free(mci); return -ENODEV; |
2f768af73 [PATCH] EDAC: dri... |
347 348 349 350 |
} /* returns count (>= 0), or negative on error */ static int __devinit r82600_init_one(struct pci_dev *pdev, |
052dfb45c drivers/edac: cle... |
351 |
const struct pci_device_id *ent) |
2f768af73 [PATCH] EDAC: dri... |
352 |
{ |
537fba289 [PATCH] EDAC: pri... |
353 354 |
debugf0("%s() ", __func__); |
2f768af73 [PATCH] EDAC: dri... |
355 |
|
ee6583f6e PCI: fix typos pc... |
356 |
/* don't need to call pci_enable_device() */ |
2f768af73 [PATCH] EDAC: dri... |
357 358 |
return r82600_probe1(pdev, ent->driver_data); } |
2f768af73 [PATCH] EDAC: dri... |
359 360 361 |
static void __devexit r82600_remove_one(struct pci_dev *pdev) { struct mem_ctl_info *mci; |
537fba289 [PATCH] EDAC: pri... |
362 363 |
debugf0("%s() ", __func__); |
2f768af73 [PATCH] EDAC: dri... |
364 |
|
456a2f955 drivers/edac: dri... |
365 366 |
if (r82600_pci) edac_pci_release_generic_ctl(r82600_pci); |
37f04581a [PATCH] EDAC: PCI... |
367 |
if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) |
18dbc337a [PATCH] EDAC: pro... |
368 369 370 |
return; edac_mc_free(mci); |
2f768af73 [PATCH] EDAC: dri... |
371 |
} |
2f768af73 [PATCH] EDAC: dri... |
372 |
static const struct pci_device_id r82600_pci_tbl[] __devinitdata = { |
e7ecd8910 [PATCH] EDAC: for... |
373 |
{ |
cddbfcacf drivers/edac: Lin... |
374 375 |
PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID) }, |
e7ecd8910 [PATCH] EDAC: for... |
376 |
{ |
cddbfcacf drivers/edac: Lin... |
377 378 |
0, } /* 0 terminated list. */ |
2f768af73 [PATCH] EDAC: dri... |
379 380 381 |
}; MODULE_DEVICE_TABLE(pci, r82600_pci_tbl); |
2f768af73 [PATCH] EDAC: dri... |
382 |
static struct pci_driver r82600_driver = { |
680cbbbb0 [PATCH] EDAC: nam... |
383 |
.name = EDAC_MOD_STR, |
2f768af73 [PATCH] EDAC: dri... |
384 385 386 387 |
.probe = r82600_init_one, .remove = __devexit_p(r82600_remove_one), .id_table = r82600_pci_tbl, }; |
da9bb1d27 [PATCH] EDAC: cor... |
388 |
static int __init r82600_init(void) |
2f768af73 [PATCH] EDAC: dri... |
389 |
{ |
c3c52bce6 edac: fix module ... |
390 391 |
/* Ensure that the OPSTATE is set correctly for POLL or NMI */ opstate_init(); |
2f768af73 [PATCH] EDAC: dri... |
392 393 |
return pci_register_driver(&r82600_driver); } |
2f768af73 [PATCH] EDAC: dri... |
394 395 396 397 |
static void __exit r82600_exit(void) { pci_unregister_driver(&r82600_driver); } |
2f768af73 [PATCH] EDAC: dri... |
398 399 |
module_init(r82600_init); module_exit(r82600_exit); |
2f768af73 [PATCH] EDAC: dri... |
400 401 |
MODULE_LICENSE("GPL"); MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD Ltd. " |
052dfb45c drivers/edac: cle... |
402 |
"on behalf of EADS Astrium"); |
2f768af73 [PATCH] EDAC: dri... |
403 404 405 406 407 |
MODULE_DESCRIPTION("MC support for Radisys 82600 memory controllers"); module_param(disable_hardware_scrub, bool, 0644); MODULE_PARM_DESC(disable_hardware_scrub, "If set, disable the chipset's automatic scrub for CEs"); |
c3c52bce6 edac: fix module ... |
408 409 410 |
module_param(edac_op_state, int, 0444); MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); |