Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
i82443bxgx_edac.c
Go to the documentation of this file.
1 /*
2  * Intel 82443BX/GX (440BX/GX chipset) Memory Controller EDAC kernel
3  * module (C) 2006 Tim Small
4  *
5  * This file may be distributed under the terms of the GNU General
6  * Public License.
7  *
8  * Written by Tim Small <[email protected]>, based on work by Linux
9  * Networx, Thayne Harbaugh, Dan Hollis <goemon at anime dot net> and
10  * others.
11  *
12  * 440GX fix by Jason Uhlenkott <[email protected]>.
13  *
14  * Written with reference to 82443BX Host Bridge Datasheet:
15  * http://download.intel.com/design/chipsets/datashts/29063301.pdf
16  * references to this document given in [].
17  *
18  * This module doesn't support the 440LX, but it may be possible to
19  * make it do so (the 440LX's register definitions are different, but
20  * not completely so - I haven't studied them in enough detail to know
21  * how easy this would be).
22  */
23 
24 #include <linux/module.h>
25 #include <linux/init.h>
26 
27 #include <linux/pci.h>
28 #include <linux/pci_ids.h>
29 
30 
31 #include <linux/edac.h>
32 #include "edac_core.h"
33 
34 #define I82443_REVISION "0.1"
35 
36 #define EDAC_MOD_STR "i82443bxgx_edac"
37 
38 /* The 82443BX supports SDRAM, or EDO (EDO for mobile only), "Memory
39  * Size: 8 MB to 512 MB (1GB with Registered DIMMs) with eight memory
40  * rows" "The 82443BX supports multiple-bit error detection and
41  * single-bit error correction when ECC mode is enabled and
42  * single/multi-bit error detection when correction is disabled.
43  * During writes to the DRAM, the 82443BX generates ECC for the data
44  * on a QWord basis. Partial QWord writes require a read-modify-write
45  * cycle when ECC is enabled."
46 */
47 
48 /* "Additionally, the 82443BX ensures that the data is corrected in
49  * main memory so that accumulation of errors is prevented. Another
50  * error within the same QWord would result in a double-bit error
51  * which is unrecoverable. This is known as hardware scrubbing since
52  * it requires no software intervention to correct the data in memory."
53  */
54 
55 /* [Also see page 100 (section 4.3), "DRAM Interface"]
56  * [Also see page 112 (section 4.6.1.4), ECC]
57  */
58 
59 #define I82443BXGX_NR_CSROWS 8
60 #define I82443BXGX_NR_CHANS 1
61 #define I82443BXGX_NR_DIMMS 4
62 
63 /* 82443 PCI Device 0 */
64 #define I82443BXGX_NBXCFG 0x50 /* 32bit register starting at this PCI
65  * config space offset */
66 #define I82443BXGX_NBXCFG_OFFSET_NON_ECCROW 24 /* Array of bits, zero if
67  * row is non-ECC */
68 #define I82443BXGX_NBXCFG_OFFSET_DRAM_FREQ 12 /* 2 bits,00=100MHz,10=66 MHz */
69 
70 #define I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY 7 /* 2 bits: */
71 #define I82443BXGX_NBXCFG_INTEGRITY_NONE 0x0 /* 00 = Non-ECC */
72 #define I82443BXGX_NBXCFG_INTEGRITY_EC 0x1 /* 01 = EC (only) */
73 #define I82443BXGX_NBXCFG_INTEGRITY_ECC 0x2 /* 10 = ECC */
74 #define I82443BXGX_NBXCFG_INTEGRITY_SCRUB 0x3 /* 11 = ECC + HW Scrub */
75 
76 #define I82443BXGX_NBXCFG_OFFSET_ECC_DIAG_ENABLE 6
77 
78 /* 82443 PCI Device 0 */
79 #define I82443BXGX_EAP 0x80 /* 32bit register starting at this PCI
80  * config space offset, Error Address
81  * Pointer Register */
82 #define I82443BXGX_EAP_OFFSET_EAP 12 /* High 20 bits of error address */
83 #define I82443BXGX_EAP_OFFSET_MBE BIT(1) /* Err at EAP was multi-bit (W1TC) */
84 #define I82443BXGX_EAP_OFFSET_SBE BIT(0) /* Err at EAP was single-bit (W1TC) */
85 
86 #define I82443BXGX_ERRCMD 0x90 /* 8bit register starting at this PCI
87  * config space offset. */
88 #define I82443BXGX_ERRCMD_OFFSET_SERR_ON_MBE BIT(1) /* 1 = enable */
89 #define I82443BXGX_ERRCMD_OFFSET_SERR_ON_SBE BIT(0) /* 1 = enable */
90 
91 #define I82443BXGX_ERRSTS 0x91 /* 16bit register starting at this PCI
92  * config space offset. */
93 #define I82443BXGX_ERRSTS_OFFSET_MBFRE 5 /* 3 bits - first err row multibit */
94 #define I82443BXGX_ERRSTS_OFFSET_MEF BIT(4) /* 1 = MBE occurred */
95 #define I82443BXGX_ERRSTS_OFFSET_SBFRE 1 /* 3 bits - first err row singlebit */
96 #define I82443BXGX_ERRSTS_OFFSET_SEF BIT(0) /* 1 = SBE occurred */
97 
98 #define I82443BXGX_DRAMC 0x57 /* 8bit register starting at this PCI
99  * config space offset. */
100 #define I82443BXGX_DRAMC_OFFSET_DT 3 /* 2 bits, DRAM Type */
101 #define I82443BXGX_DRAMC_DRAM_IS_EDO 0 /* 00 = EDO */
102 #define I82443BXGX_DRAMC_DRAM_IS_SDRAM 1 /* 01 = SDRAM */
103 #define I82443BXGX_DRAMC_DRAM_IS_RSDRAM 2 /* 10 = Registered SDRAM */
104 
105 #define I82443BXGX_DRB 0x60 /* 8x 8bit registers starting at this PCI
106  * config space offset. */
107 
108 /* FIXME - don't poll when ECC disabled? */
109 
111  u32 eap;
112 };
113 
114 static struct edac_pci_ctl_info *i82443bxgx_pci;
115 
116 static struct pci_dev *mci_pdev; /* init dev: in case that AGP code has
117  * already registered driver
118  */
119 
120 static int i82443bxgx_registered = 1;
121 
122 static void i82443bxgx_edacmc_get_error_info(struct mem_ctl_info *mci,
124  *info)
125 {
126  struct pci_dev *pdev;
127  pdev = to_pci_dev(mci->pdev);
128  pci_read_config_dword(pdev, I82443BXGX_EAP, &info->eap);
129  if (info->eap & I82443BXGX_EAP_OFFSET_SBE)
130  /* Clear error to allow next error to be reported [p.61] */
131  pci_write_bits32(pdev, I82443BXGX_EAP,
134 
135  if (info->eap & I82443BXGX_EAP_OFFSET_MBE)
136  /* Clear error to allow next error to be reported [p.61] */
137  pci_write_bits32(pdev, I82443BXGX_EAP,
140 }
141 
142 static int i82443bxgx_edacmc_process_error_info(struct mem_ctl_info *mci,
143  struct
145  *info, int handle_errors)
146 {
147  int error_found = 0;
148  u32 eapaddr, page, pageoffset;
149 
150  /* bits 30:12 hold the 4kb block in which the error occurred
151  * [p.61] */
152  eapaddr = (info->eap & 0xfffff000);
153  page = eapaddr >> PAGE_SHIFT;
154  pageoffset = eapaddr - (page << PAGE_SHIFT);
155 
156  if (info->eap & I82443BXGX_EAP_OFFSET_SBE) {
157  error_found = 1;
158  if (handle_errors)
160  page, pageoffset, 0,
161  edac_mc_find_csrow_by_page(mci, page),
162  0, -1, mci->ctl_name, "");
163  }
164 
165  if (info->eap & I82443BXGX_EAP_OFFSET_MBE) {
166  error_found = 1;
167  if (handle_errors)
169  page, pageoffset, 0,
170  edac_mc_find_csrow_by_page(mci, page),
171  0, -1, mci->ctl_name, "");
172  }
173 
174  return error_found;
175 }
176 
177 static void i82443bxgx_edacmc_check(struct mem_ctl_info *mci)
178 {
179  struct i82443bxgx_edacmc_error_info info;
180 
181  edac_dbg(1, "MC%d\n", mci->mc_idx);
182  i82443bxgx_edacmc_get_error_info(mci, &info);
183  i82443bxgx_edacmc_process_error_info(mci, &info, 1);
184 }
185 
186 static void i82443bxgx_init_csrows(struct mem_ctl_info *mci,
187  struct pci_dev *pdev,
188  enum edac_type edac_mode,
189  enum mem_type mtype)
190 {
191  struct csrow_info *csrow;
192  struct dimm_info *dimm;
193  int index;
194  u8 drbar, dramc;
195  u32 row_base, row_high_limit, row_high_limit_last;
196 
197  pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
198  row_high_limit_last = 0;
199  for (index = 0; index < mci->nr_csrows; index++) {
200  csrow = mci->csrows[index];
201  dimm = csrow->channels[0]->dimm;
202 
203  pci_read_config_byte(pdev, I82443BXGX_DRB + index, &drbar);
204  edac_dbg(1, "MC%d: Row=%d DRB = %#0x\n",
205  mci->mc_idx, index, drbar);
206  row_high_limit = ((u32) drbar << 23);
207  /* find the DRAM Chip Select Base address and mask */
208  edac_dbg(1, "MC%d: Row=%d, Boundary Address=%#0x, Last = %#0x\n",
209  mci->mc_idx, index, row_high_limit,
210  row_high_limit_last);
211 
212  /* 440GX goes to 2GB, represented with a DRB of 0. */
213  if (row_high_limit_last && !row_high_limit)
214  row_high_limit = 1UL << 31;
215 
216  /* This row is empty [p.49] */
217  if (row_high_limit == row_high_limit_last)
218  continue;
219  row_base = row_high_limit_last;
220  csrow->first_page = row_base >> PAGE_SHIFT;
221  csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1;
222  dimm->nr_pages = csrow->last_page - csrow->first_page + 1;
223  /* EAP reports in 4kilobyte granularity [61] */
224  dimm->grain = 1 << 12;
225  dimm->mtype = mtype;
226  /* I don't think 440BX can tell you device type? FIXME? */
227  dimm->dtype = DEV_UNKNOWN;
228  /* Mode is global to all rows on 440BX */
229  dimm->edac_mode = edac_mode;
230  row_high_limit_last = row_high_limit;
231  }
232 }
233 
234 static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
235 {
236  struct mem_ctl_info *mci;
237  struct edac_mc_layer layers[2];
238  u8 dramc;
239  u32 nbxcfg, ecc_mode;
240  enum mem_type mtype;
241  enum edac_type edac_mode;
242 
243  edac_dbg(0, "MC:\n");
244 
245  /* Something is really hosed if PCI config space reads from
246  * the MC aren't working.
247  */
248  if (pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg))
249  return -EIO;
250 
252  layers[0].size = I82443BXGX_NR_CSROWS;
253  layers[0].is_virt_csrow = true;
254  layers[1].type = EDAC_MC_LAYER_CHANNEL;
255  layers[1].size = I82443BXGX_NR_CHANS;
256  layers[1].is_virt_csrow = false;
257  mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0);
258  if (mci == NULL)
259  return -ENOMEM;
260 
261  edac_dbg(0, "MC: mci = %p\n", mci);
262  mci->pdev = &pdev->dev;
265  pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
266  switch ((dramc >> I82443BXGX_DRAMC_OFFSET_DT) & (BIT(0) | BIT(1))) {
268  mtype = MEM_EDO;
269  break;
271  mtype = MEM_SDR;
272  break;
274  mtype = MEM_RDR;
275  break;
276  default:
277  edac_dbg(0, "Unknown/reserved DRAM type value in DRAMC register!\n");
278  mtype = -MEM_UNKNOWN;
279  }
280 
281  if ((mtype == MEM_SDR) || (mtype == MEM_RDR))
282  mci->edac_cap = mci->edac_ctl_cap;
283  else
284  mci->edac_cap = EDAC_FLAG_NONE;
285 
287  pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg);
288  ecc_mode = ((nbxcfg >> I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY) &
289  (BIT(0) | BIT(1)));
290 
291  mci->scrub_mode = (ecc_mode == I82443BXGX_NBXCFG_INTEGRITY_SCRUB)
293 
294  switch (ecc_mode) {
296  edac_mode = EDAC_NONE;
297  break;
299  edac_mode = EDAC_EC;
300  break;
303  edac_mode = EDAC_SECDED;
304  break;
305  default:
306  edac_dbg(0, "Unknown/reserved ECC state in NBXCFG register!\n");
307  edac_mode = EDAC_UNKNOWN;
308  break;
309  }
310 
311  i82443bxgx_init_csrows(mci, pdev, edac_mode, mtype);
312 
313  /* Many BIOSes don't clear error flags on boot, so do this
314  * here, or we get "phantom" errors occurring at module-load
315  * time. */
316  pci_write_bits32(pdev, I82443BXGX_EAP,
321 
322  mci->mod_name = EDAC_MOD_STR;
323  mci->mod_ver = I82443_REVISION;
324  mci->ctl_name = "I82443BXGX";
325  mci->dev_name = pci_name(pdev);
326  mci->edac_check = i82443bxgx_edacmc_check;
327  mci->ctl_page_to_phys = NULL;
328 
329  if (edac_mc_add_mc(mci)) {
330  edac_dbg(3, "failed edac_mc_add_mc()\n");
331  goto fail;
332  }
333 
334  /* allocating generic PCI control info */
335  i82443bxgx_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
336  if (!i82443bxgx_pci) {
338  "%s(): Unable to create PCI control\n",
339  __func__);
341  "%s(): PCI error report via EDAC not setup\n",
342  __func__);
343  }
344 
345  edac_dbg(3, "MC: success\n");
346  return 0;
347 
348 fail:
349  edac_mc_free(mci);
350  return -ENODEV;
351 }
352 
353 EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_probe1);
354 
355 /* returns count (>= 0), or negative on error */
356 static int __devinit i82443bxgx_edacmc_init_one(struct pci_dev *pdev,
357  const struct pci_device_id *ent)
358 {
359  int rc;
360 
361  edac_dbg(0, "MC:\n");
362 
363  /* don't need to call pci_enable_device() */
364  rc = i82443bxgx_edacmc_probe1(pdev, ent->driver_data);
365 
366  if (mci_pdev == NULL)
367  mci_pdev = pci_dev_get(pdev);
368 
369  return rc;
370 }
371 
372 static void __devexit i82443bxgx_edacmc_remove_one(struct pci_dev *pdev)
373 {
374  struct mem_ctl_info *mci;
375 
376  edac_dbg(0, "\n");
377 
378  if (i82443bxgx_pci)
379  edac_pci_release_generic_ctl(i82443bxgx_pci);
380 
381  if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
382  return;
383 
384  edac_mc_free(mci);
385 }
386 
387 EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_remove_one);
388 
389 static DEFINE_PCI_DEVICE_TABLE(i82443bxgx_pci_tbl) = {
394  {0,} /* 0 terminated list. */
395 };
396 
397 MODULE_DEVICE_TABLE(pci, i82443bxgx_pci_tbl);
398 
399 static struct pci_driver i82443bxgx_edacmc_driver = {
400  .name = EDAC_MOD_STR,
401  .probe = i82443bxgx_edacmc_init_one,
402  .remove = __devexit_p(i82443bxgx_edacmc_remove_one),
403  .id_table = i82443bxgx_pci_tbl,
404 };
405 
406 static int __init i82443bxgx_edacmc_init(void)
407 {
408  int pci_rc;
409  /* Ensure that the OPSTATE is set correctly for POLL or NMI */
410  opstate_init();
411 
412  pci_rc = pci_register_driver(&i82443bxgx_edacmc_driver);
413  if (pci_rc < 0)
414  goto fail0;
415 
416  if (mci_pdev == NULL) {
417  const struct pci_device_id *id = &i82443bxgx_pci_tbl[0];
418  int i = 0;
419  i82443bxgx_registered = 0;
420 
421  while (mci_pdev == NULL && id->vendor != 0) {
422  mci_pdev = pci_get_device(id->vendor,
423  id->device, NULL);
424  i++;
425  id = &i82443bxgx_pci_tbl[i];
426  }
427  if (!mci_pdev) {
428  edac_dbg(0, "i82443bxgx pci_get_device fail\n");
429  pci_rc = -ENODEV;
430  goto fail1;
431  }
432 
433  pci_rc = i82443bxgx_edacmc_init_one(mci_pdev, i82443bxgx_pci_tbl);
434 
435  if (pci_rc < 0) {
436  edac_dbg(0, "i82443bxgx init fail\n");
437  pci_rc = -ENODEV;
438  goto fail1;
439  }
440  }
441 
442  return 0;
443 
444 fail1:
445  pci_unregister_driver(&i82443bxgx_edacmc_driver);
446 
447 fail0:
448  if (mci_pdev != NULL)
449  pci_dev_put(mci_pdev);
450 
451  return pci_rc;
452 }
453 
454 static void __exit i82443bxgx_edacmc_exit(void)
455 {
456  pci_unregister_driver(&i82443bxgx_edacmc_driver);
457 
458  if (!i82443bxgx_registered)
459  i82443bxgx_edacmc_remove_one(mci_pdev);
460 
461  if (mci_pdev)
462  pci_dev_put(mci_pdev);
463 }
464 
465 module_init(i82443bxgx_edacmc_init);
466 module_exit(i82443bxgx_edacmc_exit);
467 
468 MODULE_LICENSE("GPL");
469 MODULE_AUTHOR("Tim Small <[email protected]> - WPAD");
470 MODULE_DESCRIPTION("EDAC MC support for Intel 82443BX/GX memory controllers");
471 
472 module_param(edac_op_state, int, 0444);
473 MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");