Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / kernel_patches / patches / bluesmoke-2.6-suse-lnxi.patch
1 Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/Kconfig
2 ===================================================================
3 --- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/Kconfig  2004-11-11 10:28:08.000000000 -0500
4 +++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/Kconfig       2004-12-17 12:45:23.000000000 -0500
5 @@ -6,6 +6,8 @@
6  
7  source "drivers/mtd/Kconfig"
8  
9 +source "drivers/bluesmoke/Kconfig"
10 +
11  source "drivers/parport/Kconfig"
12  
13  source "drivers/pnp/Kconfig"
14 Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/Makefile
15 ===================================================================
16 --- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/Makefile 2004-11-11 10:28:16.000000000 -0500
17 +++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/Makefile      2004-12-17 12:45:23.000000000 -0500
18 @@ -29,6 +29,7 @@
19  obj-$(CONFIG_IEEE1394)         += ieee1394/
20  obj-y                          += cdrom/ video/
21  obj-$(CONFIG_MTD)              += mtd/
22 +obj-$(CONFIG_BLUESMOKE)                += bluesmoke/
23  obj-$(CONFIG_PCMCIA)           += pcmcia/
24  obj-$(CONFIG_DIO)              += dio/
25  obj-$(CONFIG_SBUS)             += sbus/
26 Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/Kconfig
27 ===================================================================
28 --- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/Kconfig        1969-12-31 19:00:00.000000000 -0500
29 +++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/Kconfig     2004-12-17 12:46:23.000000000 -0500
30 @@ -0,0 +1,72 @@
31 +#
32 +#      Bluesmoke Kconfig
33 +#      Copyright (c) 2003 Linux Networx
34 +#      Licensed and distributed under the GPL
35 +#
36 +# $Id: Kconfig,v 1.4 2004/11/10 01:12:35 thayne Exp $
37 +#
38 +
39 +menu 'Bluesmoke - error detection and reporting (RAS)'
40 +
41 +config BLUESMOKE
42 +       tristate "Bluesmoke core system error reporting"
43 +       help
44 +         Bluesmoke is designed to report errors in the core system.
45 +         These are low-level errors that are reported in the CPU or
46 +         supporting chipset: memory errors, cache errors, PCI errors,
47 +         thermal throttling, etc..  If unsure, select 'Y'.
48 +
49 +
50 +comment "Reporting subsystems"
51 +       depends on BLUESMOKE
52 +
53 +config BLUESMOKE_DEBUG
54 +       bool "Debugging"
55 +       depends on BLUESMOKE
56 +       help
57 +         This turns on debugging information for the entire Bluesmoke
58 +         sub-system.  Usually you should select 'N'.
59 +
60 +config BULESMOKE_DEBUG_VERBOSE
61 +       int "Debugging verbosity (0=quiet, 3=noisy)"
62 +       depends on BLUESMOKE_DEBUG
63 +       default "0"
64 +       help
65 +         Verbosity level of Bluesmoke debug messages.
66 +
67 +config BLUESMOKE_MM_EDAC
68 +       tristate "Bluesmoke Main Memory EDAC (Error Detection And Correction) reporting"
69 +       depends on BLUESMOKE
70 +       help
71 +         Some systems are able to detect and correct errors in main
72 +         memory.  Bluesmoke can report statistics on memory error
73 +         detection and correction (EDAC - or commonly referred to ECC
74 +         errors).  Bluesmoke will also try to decode where these errors
75 +         occurred so that a particular failing memory module can be
76 +         replaced.  If unsure, select 'Y'.
77 +
78 +
79 +comment "Bluesmoke system controller/chipset support"
80 +       depends on BLUESMOKE
81 +
82 +config BLUESMOKE_AMD76X
83 +       tristate "AMD 76x (760, 762, 768)"
84 +       depends on BLUESMOKE
85 +
86 +config BLUESMOKE_E7XXX
87 +       tristate "Intel e7xxx (e7205, e7500, e7501, e7505)"
88 +       depends on BLUESMOKE
89 +
90 +config BLUESMOKE_E752X
91 +       tristate "Intel e752x (e7520)"
92 +       depends on BLUESMOKE
93 +
94 +config BLUESMOKE_I82875P
95 +       tristate "Intel 82875p"
96 +       depends on BLUESMOKE
97 +
98 +config BLUESMOKE_K8
99 +       tristate "AMD K8 (Athlon FX, Athlon 64, Opteron)"
100 +       depends on BLUESMOKE
101 +
102 +endmenu
103 Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/Makefile
104 ===================================================================
105 --- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/Makefile       1969-12-31 19:00:00.000000000 -0500
106 +++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/Makefile    2004-12-17 12:46:23.000000000 -0500
107 @@ -0,0 +1,26 @@
108 +#
109 +# Makefile for the Linux kernel bluesmoke drivers.
110 +#
111 +# Copyright 02 Jul 2003, Linux Networx (http://lnxi.com)
112 +# This file may be distributed under the terms of the
113 +# GNU General Public License.
114 +#
115 +# $Id: Makefile,v 1.4 2004/11/10 01:12:35 thayne Exp $
116 +
117 +
118 +obj-$(CONFIG_BLUESMOKE_MM_EDAC)                += bluesmoke_mc.o
119 +obj-$(CONFIG_BLUESMOKE_AMD76X)         += bluesmoke_amd76x.o 
120 +obj-$(CONFIG_BLUESMOKE_E7XXX)          += bluesmoke_e7xxx.o 
121 +obj-$(CONFIG_BLUESMOKE_E752X)          += bluesmoke_e752x.o 
122 +obj-$(CONFIG_BLUESMOKE_I82875P)                += bluesmoke_i82875p.o 
123 +obj-$(CONFIG_BLUESMOKE_K8)             += bluesmoke_k8.o 
124 +
125 +ifeq ($(PATCHLEVEL),4)
126 +
127 +export-objs    := bluesmoke_mc.o
128 +
129 +O_TARGET       := bluesmokelink.o
130 +
131 +include $(TOPDIR)/Rules.make
132 +
133 +endif
134 Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_amd76x.c
135 ===================================================================
136 --- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/bluesmoke_amd76x.c     1969-12-31 19:00:00.000000000 -0500
137 +++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_amd76x.c  2004-12-17 12:46:23.000000000 -0500
138 @@ -0,0 +1,323 @@
139 +/*
140 + * AMD 76x Memory Controller kernel module
141 + * (C) 2003 Linux Networx (http://lnxi.com)
142 + * This file may be distributed under the terms of the
143 + * GNU General Public License.
144 + *
145 + * Written by Thayne Harbaugh
146 + * Based on work by Dan Hollis <goemon at anime dot net> and others.
147 + *     http://www.anime.net/~goemon/linux-ecc/
148 + *
149 + * $Id: bluesmoke_amd76x.c,v 1.4 2004/11/10 01:12:35 thayne Exp $
150 + *
151 + */
152 +
153 +
154 +#include <linux/config.h>
155 +#include <linux/module.h>
156 +#include <linux/init.h>
157 +
158 +#include <linux/pci.h>
159 +#include <linux/pci_ids.h>
160 +
161 +#include <linux/slab.h>
162 +
163 +#include "bluesmoke_mc.h"
164 +
165 +
166 +#define AMD76X_NR_CSROWS 8
167 +#define AMD76X_NR_CHANS  1
168 +#define AMD76X_NR_DIMMS  4
169 +
170 +
171 +/* AMD 76x register addresses - device 0 function 0 - PCI bridge */
172 +#define AMD76X_ECC_MODE_STATUS 0x48    /* Mode and status of ECC (32b)
173 +                                        *
174 +                                        * 31:16 reserved
175 +                                        * 15:14 SERR enabled: x1=ue 1x=ce
176 +                                        * 13    reserved
177 +                                        * 12    diag: disabled, enabled
178 +                                        * 11:10 mode: dis, EC, ECC, ECC+scrub
179 +                                        *  9:8  status: x1=ue 1x=ce
180 +                                        *  7:4  UE cs row
181 +                                        *  3:0  CE cs row
182 +                                        */
183 +#define AMD76X_DRAM_MODE_STATUS        0x58    /* DRAM Mode and status (32b)
184 +                                        *
185 +                                        * 31:26 clock disable 5 - 0
186 +                                        * 25    SDRAM init
187 +                                        * 24    reserved
188 +                                        * 23    mode register service
189 +                                        * 22:21 suspend to RAM
190 +                                        * 20    burst refresh enable
191 +                                        * 19    refresh disable
192 +                                        * 18    reserved
193 +                                        * 17:16 cycles-per-refresh
194 +                                        * 15:8  reserved
195 +                                        *  7:0  x4 mode enable 7 - 0
196 +                                        */
197 +#define AMD76X_MEM_BASE_ADDR   0xC0    /* Memory base address (8 x 32b)
198 +                                        *
199 +                                        * 31:23 chip-select base
200 +                                        * 22:16 reserved
201 +                                        * 15:7  chip-select mask
202 +                                        *  6:3  reserved
203 +                                        *  2:1  address mode
204 +                                        *  0    chip-select enable
205 +                                        */
206 +
207 +
208 +enum amd76x_chips {
209 +       AMD761 = 0,
210 +       AMD762
211 +};
212 +
213 +
214 +struct amd76x_dev_info {
215 +       const char *ctl_name;
216 +};
217 +
218 +
219 +static const struct amd76x_dev_info amd76x_devs[] = {
220 +       [AMD761] = {
221 +               .ctl_name = "AMD761"
222 +       },
223 +       [AMD762] = {
224 +               .ctl_name = "AMD762"
225 +       },
226 +};
227 +
228 +
229 +static void amd76x_check(struct mem_ctl_info *mci)
230 +{
231 +       u32 ems;
232 +
233 +       debugf1( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
234 +
235 +       pci_read_config_dword(mci->pdev, AMD76X_ECC_MODE_STATUS, &ems);
236 +
237 +       if ( ems & BIT(8) ) {   /* UE? */
238 +               u32 ems_ue_row = (ems >> 4) & 0xf;
239 +
240 +               pci_write_bits32( mci->pdev, AMD76X_ECC_MODE_STATUS,
241 +                                 (u32)BIT(8), (u32)BIT(8) );
242 +
243 +               bluesmoke_mc_handle_ue( mci, mci->csrows[ems_ue_row].first_page,
244 +                                       0, ems_ue_row, mci->ctl_name );
245 +       }
246 +
247 +       if ( ems & BIT(9) ) {   /* CE? */
248 +               u32 ems_ce_row = ems & 0xf;
249 +
250 +               pci_write_bits32( mci->pdev, AMD76X_ECC_MODE_STATUS,
251 +                                 (u32)BIT(9), (u32)BIT(9) );
252 +
253 +               bluesmoke_mc_handle_ce( mci, mci->csrows[ems_ce_row].first_page,
254 +                                       0, 0, ems_ce_row, 0, mci->ctl_name );
255 +       }
256 +       return;
257 +}
258 +
259 +
260 +static int amd76x_probe1( struct pci_dev *pdev, int dev_idx )
261 +{
262 +       int rc = -ENODEV;
263 +       int index;
264 +       struct mem_ctl_info *mci = NULL;
265 +       enum edac_type ems_modes[] = { EDAC_NONE,
266 +                                      EDAC_EC,
267 +                                      EDAC_SECDED,
268 +                                      EDAC_SECDED };
269 +       u32 ems;
270 +       u32 ems_mode;
271 +
272 +       debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
273 +
274 +       pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS, &ems);
275 +       ems_mode = ( ems >> 10 ) & 0x3;
276 +
277 +       mci = bluesmoke_mc_init_structs(0,
278 +                                       AMD76X_NR_CSROWS,
279 +                                       AMD76X_NR_CHANS);
280 +
281 +       if ( ! mci ) {
282 +               rc = -ENOMEM;
283 +               goto FAIL_FINISHED;
284 +       }
285 +
286 +       debugf0( "MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci );
287 +
288 +       mci->pdev = pdev;
289 +       mci->mtype_cap = MEM_FLAG_RDDR;
290 +
291 +       mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
292 +       if ( ems_mode ) {
293 +               mci->edac_cap = EDAC_FLAG_EC | EDAC_FLAG_SECDED;
294 +       } else {
295 +               mci->edac_cap = EDAC_FLAG_NONE;
296 +       }
297 +
298 +       mci->mod_name = BS_MOD_STR;
299 +       mci->mod_ver = "$Revision: 1.4 $";
300 +       mci->ctl_name = amd76x_devs[dev_idx].ctl_name;
301 +       mci->edac_check = amd76x_check;
302 +       mci->clear_err = NULL;
303 +       mci->ctl_page_to_phys = NULL;
304 +
305 +       for ( index = 0; index < mci->nr_csrows; index++ ) {
306 +               struct csrow_info *csrow = &mci->csrows[ index ];
307 +               u32 mba;
308 +               u32 mba_base;
309 +               u32 mba_mask;
310 +               u32 dms;
311 +
312 +               /* find the DRAM Chip Select Base address and mask */
313 +               pci_read_config_dword( mci->pdev,
314 +                                      AMD76X_MEM_BASE_ADDR + (index*4),
315 +                                      &mba );
316 +
317 +               if ( ! (mba & BIT(0)) ) {
318 +                       continue;
319 +               }
320 +
321 +               mba_base = mba & 0xff800000UL;
322 +               mba_mask = ((mba & 0xff80) << 16) | 0x7fffffUL;
323 +
324 +               pci_read_config_dword( mci->pdev,
325 +                                      AMD76X_DRAM_MODE_STATUS,
326 +                                      &dms );
327 +
328 +               csrow->first_page = mba_base >> PAGE_SHIFT;
329 +               csrow->nr_pages = (mba_mask + 1) >> PAGE_SHIFT;
330 +               csrow->last_page = csrow->first_page + csrow->nr_pages - 1;
331 +               csrow->page_mask = mba_mask >> PAGE_SHIFT;
332 +               csrow->grain = csrow->nr_pages << PAGE_SHIFT;
333 +               csrow->mtype = MEM_RDDR;
334 +               csrow->dtype = ((dms >> index) & 0x1) ? DEV_X4 : DEV_UNKNOWN;
335 +               csrow->edac_mode = ems_modes[ ems_mode ];
336 +       }
337 +
338 +       /* clear counters */
339 +       pci_write_bits32( mci->pdev, AMD76X_ECC_MODE_STATUS,
340 +                         (u32)(0x3 << 8), (u32)(0x3 << 8) );
341 +
342 +       if ( 0 != bluesmoke_mc_add_mc( mci ) ) {
343 +               debugf3( "MC: " __FILE__
344 +                        ": %s(): failed bluesmoke_mc_add_mc()\n", __func__ );
345 +               goto FAIL_FINISHED;
346 +       }
347 +
348 +       /* get this far and it's successful */
349 +       debugf3( "MC: " __FILE__ ": %s(): success\n", __func__ );
350 +       rc = 0;
351 +       goto FINISHED;
352 +
353 + FAIL_FINISHED:
354 +       if ( mci ) {
355 +               kfree( mci );
356 +       }
357 +
358 + FINISHED:
359 +       return( rc );
360 +}
361 +
362 +
363 +#ifdef CONFIG_PM
364 +
365 +static int amd76x_suspend (struct pci_dev *pdev, u32 state)
366 +{
367 +       debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
368 +
369 +       return -ENOSYS;
370 +}
371 +
372 +
373 +static int amd76x_resume (struct pci_dev *pdev)
374 +{
375 +       debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
376 +
377 +       return -ENOSYS;
378 +}
379 +
380 +#endif /* CONFIG_PM */
381 +
382 +
383 +/* returns count (>= 0), or negative on error */
384 +static int __devinit amd76x_init_one( struct pci_dev *pdev,
385 +                                     const struct pci_device_id *ent )
386 +{
387 +       debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
388 +
389 +       /* don't need to call pci_device_enable() */
390 +       return amd76x_probe1( pdev, ent->driver_data );
391 +}
392 +
393 +
394 +static void __devexit amd76x_remove_one( struct pci_dev *pdev )
395 +{
396 +       struct mem_ctl_info *mci;
397 +
398 +       debugf0( __FILE__ ": %s()\n", __func__);
399 +
400 +       if ( NULL == ( mci = bluesmoke_mc_find_mci_by_pdev( pdev ) ) ) {
401 +               goto FINISHED;
402 +       }
403 +
404 +       if ( 0 != bluesmoke_mc_del_mc( mci ) ) {
405 +               goto FINISHED;
406 +       }
407 +
408 +       kfree( mci );
409 +
410 + FINISHED:
411 +       return;
412 +}
413 +
414 +
415 +static const struct pci_device_id amd76x_pci_tbl[] __devinitdata = {
416 +       { PCI_VEND_DEV( AMD, FE_GATE_700C ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD762 },
417 +       { PCI_VEND_DEV( AMD, FE_GATE_700E ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD761 },
418 +       {0,}                                            /* 0 terminated list. */
419 +};
420 +
421 +MODULE_DEVICE_TABLE(pci, amd76x_pci_tbl);
422 +
423 +
424 +static struct pci_driver amd76x_driver = {
425 +       .name           = BS_MOD_STR,
426 +       .probe          = amd76x_init_one,
427 +       .remove         = __devexit_p(amd76x_remove_one),
428 +       .id_table       = amd76x_pci_tbl,
429 +#ifdef CONFIG_PM
430 +       .suspend        = amd76x_suspend,
431 +       .resume         = amd76x_resume,
432 +#endif /* CONFIG_PM */
433 +};
434 +
435 +
436 +int __init amd76x_init(void)
437 +{
438 +       int pci_rc;
439 +
440 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
441 +       pci_rc = pci_module_init( &amd76x_driver );
442 +       if ( pci_rc < 0 ) return pci_rc;
443 +
444 +       return 0;
445 +}
446 +
447 +
448 +static void __exit amd76x_exit(void)
449 +{
450 +       debugf3( "MC: "  __FILE__ ": %s()\n", __func__ );
451 +       pci_unregister_driver( &amd76x_driver );
452 +}
453 +
454 +
455 +module_init(amd76x_init);
456 +module_exit(amd76x_exit);
457 +
458 +
459 +MODULE_LICENSE("GPL");
460 +MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh");
461 +MODULE_DESCRIPTION("MC support for AMD 76x memory controllers");
462 Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_e752x.c
463 ===================================================================
464 --- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/bluesmoke_e752x.c      1969-12-31 19:00:00.000000000 -0500
465 +++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_e752x.c   2004-12-17 12:46:23.000000000 -0500
466 @@ -0,0 +1,1027 @@
467 +/*
468 + * Intel e752x Memory Controller kernel module
469 + * (C) 2004 Linux Networx (http://lnxi.com)
470 + * This file may be distributed under the terms of the
471 + * GNU General Public License.
472 + *
473 + * See "enum e752x_chips" below for supported chipsets
474 + *
475 + * Written by Tom Zimmerman
476 + *
477 + * Contributors:
478 + *     Thayne Harbaugh (Linux Networx)
479 + *
480 + * $Id: bluesmoke_e752x.c,v 1.5 2004/11/18 22:19:46 thayne Exp $
481 + *
482 + */
483 +
484 +
485 +#include <linux/config.h>
486 +#include <linux/module.h>
487 +#include <linux/init.h>
488 +
489 +#include <linux/pci.h>
490 +#include <linux/pci_ids.h>
491 +
492 +#include <linux/slab.h>
493 +
494 +#include "bluesmoke_mc.h"
495 +
496 +
497 +#ifndef PCI_DEVICE_ID_INTEL_7520_0     
498 +#define PCI_DEVICE_ID_INTEL_7520_0      0x3590
499 +#endif /* PCI_DEVICE_ID_INTEL_7520_0      */
500 +
501 +#ifndef PCI_DEVICE_ID_INTEL_7520_1_ERR 
502 +#define PCI_DEVICE_ID_INTEL_7520_1_ERR  0x3591
503 +#endif /* PCI_DEVICE_ID_INTEL_7520_1_ERR  */
504 +
505 +
506 +#define E752X_NR_CSROWS                8       /* number of csrows */
507 +
508 +
509 +/* E752X register addresses - device 0 function 0 */
510 +#define E752X_DRB              0x60    /* DRAM row boundary register (8b) */
511 +#define E752X_DRA              0x70    /* DRAM row attribute register (8b) */
512 +                                       /*
513 +                                        * 31:30   Device width row 7 
514 +                                        *      01=x8 10=x4 11=x8 DDR2
515 +                                        * 27:26   Device width row 6
516 +                                        * 23:22   Device width row 5
517 +                                        * 19:20   Device width row 4
518 +                                        * 15:14   Device width row 3
519 +                                        * 11:10   Device width row 2
520 +                                        *  7:6    Device width row 1
521 +                                        *  3:2    Device width row 0
522 +                                        */
523 +#define E752X_DRC              0x7C    /* DRAM controller mode reg (32b) */
524 +                                       /*
525 +                                        * 22    Number channels 0=1,1=2
526 +                                        * 19:18 DRB Granularity 32/64MB
527 +                                        */
528 +#define E752X_DRM              0x80    /* Dimm mapping register */
529 +#define E752X_DDRCSR           0x9A    /* DDR control and status reg (16b) */
530 +                                       /*
531 +                                        * 14:12 1 single A, 2 single B, 3 dual
532 +                                        */
533 +#define E752X_TOLM             0xC4    /* DRAM top of low memory reg (16b) */
534 +#define E752X_REMAPBASE                0xC6    /* DRAM remap base address reg (16b) */
535 +#define E752X_REMAPLIMIT       0xC8    /* DRAM remap limit address reg (16b) */
536 +#define E752X_REMAPOFFSET      0xCA    /* DRAM remap limit offset reg (16b) */
537 +
538 +/* E752X register addresses - device 0 function 1 */
539 +#define E752X_FERR_GLOBAL      0x40    /* Global first error register (32b)*/
540 +#define E752X_NERR_GLOBAL      0x44    /* Global next error register (32b) */
541 +#define E752X_HI_FERR          0x50    /* Hub interface first error reg (8b)*/
542 +#define E752X_HI_NERR          0x52    /* Hub interface next error reg (8b)*/
543 +#define E752X_HI_ERRMASK       0x54    /* Hub interface error mask reg (8b)*/
544 +#define E752X_HI_SMICMD                0x5A    /* Hub interface SMI command reg (8b)*/
545 +#define E752X_SYSBUS_FERR      0x60    /* System buss first error reg (16b)*/
546 +#define E752X_SYSBUS_NERR      0x62    /* System buss next error reg (16b)*/
547 +#define E752X_SYSBUS_ERRMASK   0x64    /* System buss error mask reg (16b) */
548 +#define E752X_SYSBUS_SMICMD    0x6A    /* System buss SMI command reg (16b) */
549 +#define E752X_BUF_FERR         0x70    /* Memory buffer first error reg (8b)*/
550 +#define E752X_BUF_NERR         0x72    /* Memory buffer next error reg (8b)*/
551 +#define E752X_BUF_ERRMASK      0x74    /* Memory buffer error mask reg (8b)*/
552 +#define E752X_BUF_SMICMD       0x7A    /* Memory buffer SMI command reg (8b)*/
553 +#define E752X_DRAM_FERR                0x80    /* DRAM first error register (16b) */
554 +#define E752X_DRAM_NERR                0x82    /* DRAM next error register (16b) */
555 +#define E752X_DRAM_ERRMASK     0x84    /* DRAM error mask register (8b) */
556 +#define E752X_DRAM_SMICMD      0x8A    /* DRAM SMI command register (8b) */
557 +#define E752X_DRAM_RETRY_ADD   0xAC    /* DRAM Retry address register (32b) */
558 +#define E752X_DRAM_CELOG1_ADD  0xA0    /* DRAM first correctable memory */
559 +                                       /*     error address register (32b) */
560 +                                       /*
561 +                                        * 31    Reserved
562 +                                        * 30:2  CE address (64 byte block 34:6)
563 +                                        * 1     Reserved
564 +                                        * 0     HiLoCS
565 +                                        */
566 +#define E752X_DRAM_CELOG2_ADD  0xC8    /* DRAM first correctable memory */
567 +                                       /*     error address register (32b) */
568 +                                       /*
569 +                                        * 31    Reserved
570 +                                        * 30:2  CE address (64 byte block 34:6)
571 +                                        * 1     Reserved
572 +                                        * 0     HiLoCS
573 +                                        */
574 +#define E752X_DRAM_UELOG_ADD   0xA4    /* DRAM first uncorrectable memory */
575 +                                       /*     error address register (32b) */
576 +                                       /*
577 +                                        * 31    Reserved
578 +                                        * 30:2  CE address (64 byte block 34:6)
579 +                                        * 1     Reserved
580 +                                        * 0     HiLoCS
581 +                                        */
582 +#define E752X_DRAM_UELOGS_ADD  0xA8    /* DRAM first uncorrectable scrub memory */
583 +                                       /*     error address register (32b) */
584 +                                       /*
585 +                                        * 31    Reserved
586 +                                        * 30:2  CE address (64 byte block 34:6)
587 +                                        * 1     Reserved
588 +                                        * 0     HiLoCS
589 +                                        */
590 +#define E752X_DRAM_CELOG1_SYNDROME 0xC4        /* DRAM first correctable memory */
591 +                                       /*     error syndrome register (16b) */
592 +#define E752X_DRAM_CELOG2_SYNDROME 0xC6        /* DRAM second correctable memory */
593 +                                       /*     error syndrome register (16b) */
594 +#define E752X_DEVPRES1         0xF4    /* Device Present 1 register (8b) */
595 +
596 +/* ICH5R register addresses - device 30 function 0 */
597 +#define ICH5R_PCI_STAT         0x06    /* PCI status register (16b) */
598 +#define ICH5R_PCI_2ND_STAT     0x1E    /* PCI status secondary reg (16b) */
599 +#define ICH5R_PCI_BRIDGE_CTL   0x3E    /* PCI bridge control register (16b) */
600 +
601 +enum e752x_chips {
602 +       E7520 = 0,
603 +};
604 +
605 +
606 +struct e752x_pvt {
607 +       struct pci_dev *bridge_ck;
608 +       struct pci_dev *dev_d0f0;
609 +       struct pci_dev *dev_d0f1;
610 +       u32 tolm;
611 +       u32 remapbase;
612 +       u32 remaplimit;
613 +       int mc_symmetric;
614 +       u8 map[8];
615 +       int map_type;
616 +       const struct e752x_dev_info *dev_info;
617 +};
618 +
619 +
620 +struct e752x_dev_info {
621 +       u16 err_dev;
622 +       const char *ctl_name;
623 +};
624 +
625 +
626 +static const struct e752x_dev_info e752x_devs[] = {
627 +       [E7520] = {
628 +               .err_dev  = PCI_DEVICE_ID_INTEL_7520_1_ERR,
629 +               .ctl_name = "E7520"
630 +       },
631 +};
632 +
633 +
634 +/* FIXME - is this valid for both SECDED and S4ECD4ED? */
635 +static inline int e752x_find_channel(u16 syndrome)
636 +{
637 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
638 +
639 +       if((syndrome & 0xff00)==0)
640 +               return(0);
641 +       if((syndrome & 0x00ff)==0)
642 +               return(1);
643 +       if((syndrome & 0xf000)==0)
644 +               return(0);
645 +       if((syndrome & 0x0f00)==0)
646 +               return(0);
647 +       return(1);
648 +}
649 +
650 +
651 +static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
652 +                                     unsigned long page)
653 +{
654 +       u32 remap;
655 +       struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
656 +
657 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
658 +
659 +       if(page < pvt->tolm)
660 +               return(page);
661 +       if((page >= 0x100000)&&(page < pvt->remapbase))
662 +               return(page);
663 +       remap = (page - pvt->tolm) + pvt->remapbase;
664 +       if(remap < pvt->remaplimit)
665 +               return(remap);  
666 +       printk(KERN_ERR "Invalid page %lx - out of range\n", page);
667 +       return(pvt->tolm-1);
668 +}
669 +
670 +
671 +static void process_ce(struct mem_ctl_info *mci, u16 error_one, 
672 +                       u32 celog1_add, u16 celog1_syndrome)
673 +{
674 +       u32 error_1b, page;
675 +       u16 syndrome;
676 +       int row;
677 +       int channel;
678 +       int i;
679 +       struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
680 +
681 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
682 +
683 +       if(error_one&0x0101) {
684 +               /* read the error address */
685 +//             pci_read_config_dword(pvt->bridge_ck,E752X_DRAM_CELOG1_ADD,
686 +//                                     &error_1b);
687 +               error_1b = celog1_add;
688 +               page = error_1b >> (PAGE_SHIFT-4);  /* convert the addr to 4k page */
689 +               /* read the syndrome */
690 +//             pci_read_config_word(pvt->bridge_ck,E752X_DRAM_CELOG1_SYNDROME,
691 +//                             &syndrome);
692 +               syndrome = celog1_syndrome;
693 +               /* FIXME - check for -1 */
694 +               if (pvt->mc_symmetric) {
695 +                       row = ((page >>1)&3); /* chip select are bits 14 & 13 */
696 +       printk( KERN_WARNING
697 +               "Test row %d Table %d %d %d %d %d %d %d %d\n",
698 +               row,pvt->map[0],pvt->map[1],pvt->map[2],pvt->map[3],pvt->map[4],
699 +                       pvt->map[5],pvt->map[6],pvt->map[7]);
700 +
701 +                       /* test for channel remapping */
702 +                       for(i=0;i<8;i++) {
703 +                               if(pvt->map[i] == row)
704 +                                       break;
705 +                       }
706 +       printk( KERN_WARNING
707 +               "Test computed row %d\n",i); 
708 +                       if(i<8) {
709 +                               row = i;
710 +                       }
711 +                       else {
712 +                               printk( KERN_WARNING 
713 +                                       "MC%d: row %d not found in remap table\n",
714 +                                       mci->mc_idx,row);
715 +                       }
716 +
717 +
718 +               } else {
719 +                       row = bluesmoke_mc_find_csrow_by_page( mci, page );
720 +               }
721 +               if(error_one&1)
722 +                       channel = 0; /* 0 = channel A */
723 +               else
724 +                       channel = 1; /* 1 = channel B */
725 +
726 +               if(!pvt->map_type)
727 +                       row = 7 - row;
728 +               bluesmoke_mc_handle_ce( mci, page, 0, syndrome,
729 +                                       row, channel, "e752x CE" );
730 +       }
731 +}
732 +
733 +
734 +static void process_ue(struct mem_ctl_info *mci, u16 error_one,
735 +                       u32 uelog_add, u32 uelogs_add)
736 +{
737 +       u32 error_2b, block_page;
738 +       int row;
739 +       struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
740 +
741 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
742 +
743 +       if(error_one & 0x0202) {
744 +               error_2b = uelog_add;
745 +               /* convert to 4k address */
746 +               block_page = error_2b >> (PAGE_SHIFT - 4);
747 +               if (pvt->mc_symmetric) {
748 +                       /* chip select are bits 14 & 13 */
749 +                       row = ((block_page >>1)&3);
750 +               }
751 +               else {
752 +                       row = bluesmoke_mc_find_csrow_by_page(mci, block_page);
753 +               }
754 +               bluesmoke_mc_handle_ue( mci, block_page, 0, row, 
755 +                               "e752x UE from Read" );
756 +       }
757 +       if(error_one & 0x0404) {
758 +               error_2b = uelogs_add;
759 +               /* convert to 4k address */
760 +               block_page = error_2b >> (PAGE_SHIFT - 4);
761 +               if (pvt->mc_symmetric) {
762 +                       /* chip select are bits 14 & 13 */
763 +                       row = ((block_page >>1)&3);
764 +               }
765 +               else {
766 +                       row = bluesmoke_mc_find_csrow_by_page(mci, block_page);
767 +               }
768 +               bluesmoke_mc_handle_ue( mci, block_page, 0, row, 
769 +                               "e752x UE from Scruber" );
770 +       }
771 +}
772 +
773 +#if 0
774 +static void process_ue_no_info(struct mem_ctl_info *mci)
775 +{
776 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
777 +
778 +       bluesmoke_mc_handle_ue_no_info( mci, "e752x UE log register overflow" );
779 +}
780 +#endif
781 +
782 +static void process_ue_no_info_wr(struct mem_ctl_info *mci)
783 +{
784 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
785 +
786 +       bluesmoke_mc_handle_ue_no_info( mci, "e752x UE log memory write" );
787 +}
788 +
789 +static void process_ded_retry(struct mem_ctl_info *mci,u16 error,u32 retry_add)
790 +{
791 +       u32 error_1b, page;
792 +       int row;
793 +       struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
794 +
795 +       error_1b = retry_add;
796 +       page = error_1b >> (PAGE_SHIFT-4);  /* convert the addr to 4k page */
797 +       if (pvt->mc_symmetric) {
798 +               row = ((page >>1)&3); /* chip select are bits 14 & 13 */
799 +       } else {
800 +               row = bluesmoke_mc_find_csrow_by_page( mci, page );
801 +       }
802 +       printk( KERN_WARNING 
803 +                 "MC%d: CE page 0x%lx, row %d : Memory read retry\n",
804 +                 mci->mc_idx,(long unsigned int)page,row);
805 +}
806 +
807 +static void process_threshold_ce(struct mem_ctl_info *mci,u16 error)
808 +{
809 +       printk( KERN_WARNING
810 +               "MC%d: Memory threshold CE\n",mci->mc_idx);
811 +}
812 +                       
813 +char *global_message[11]= {"PCI Express C1","PCI Express C","PCI Express B1",
814 +                          "PCI Express B","PCI Express A1","PCI Express A",
815 +                          "DMA Controler","HUB Interface","System Bus",
816 +                          "DRAM Controler","Internal Buffer"};
817 +char *fatal_message[2]={"Non-Fatal ","Fatal "};
818 +
819 +static void global_error(int fatal, u32 errors)
820 +{
821 +       int i;
822 +
823 +       for(i=0;i<11;i++) {
824 +               if(errors & (1<<i)) {
825 +                       printk( KERN_WARNING "%sError %s\n",
826 +                                       fatal_message[fatal],
827 +                                       global_message[i]);
828 +               }
829 +       }       
830 +}
831 +
832 +char *hub_message[7]= {"HI Address or Command Parity","HI Illegal Access",
833 +                      "HI Internal Parity","Out of Range Access",
834 +                      "HI Data Parity","Enhanced Config Access",
835 +                      "Hub Interface Target Abort"};
836 +;
837 +static void hub_error(int fatal, u8 errors)
838 +{
839 +       int i;
840 +
841 +       for(i=0;i<7;i++) {
842 +               if(errors & (1<<i)) {
843 +                       printk( KERN_WARNING "%sError %s\n",
844 +                                       fatal_message[fatal],
845 +                                       hub_message[i]);
846 +               }
847 +       }       
848 +}
849 +
850 +char *membuf_message[4]= {"Internal PMWB to DRAM parity",
851 +                       "Internal PMWB to System Bus Parity",
852 +                       "Internal System Bus or IO to PMWB Parity",
853 +                       "Internal DRAM to PMWB Parity"};
854 +;
855 +static void membuf_error(u8 errors)
856 +{
857 +       int i;
858 +
859 +       for(i=0;i<4;i++) {
860 +               if(errors & (1<<i)) {
861 +                       printk( KERN_WARNING "Non-Fatal Error %s\n",
862 +                                       membuf_message[i]);
863 +               }
864 +       }       
865 +}
866 +
867 +char *sysbus_message[10]= {"Addr or Request Parity",
868 +                       "Data Strobe Glitch",
869 +                       "Addr Strobe Glitch",
870 +                       "Data Parity",
871 +                       "Addr Above TOM",
872 +                       "Non DRAM Lock Error",
873 +                       "MCERR", "BINIT",
874 +                       "Memory Parity",
875 +                       "IO Subsystem Parity"};
876 +
877 +static void sysbus_error(int fatal, u32 errors)
878 +{
879 +       int i;
880 +
881 +       for(i=0;i<10;i++) {
882 +               if(errors & (1<<i)) {
883 +                       printk( KERN_WARNING "%sError System Bus %s\n",
884 +                                       fatal_message[fatal],
885 +                                       global_message[i]);
886 +               }
887 +       }       
888 +}
889 +
890 +static void e752x_check(struct mem_ctl_info *mci)
891 +{
892 +       int i;
893 +       u8   stat8;
894 +       u16  error_one, error_next, stat;
895 +       u32  stat32,error32;
896 +       /* Snap shot of error registers */
897 +       u8      hi_ferr;
898 +       u8      hi_nerr;
899 +       u16     sysbus_ferr;
900 +       u16     sysbus_nerr;
901 +       u8      buf_ferr;
902 +       u8      buf_nerr;
903 +       u16     dram_ferr;
904 +       u16     dram_nerr;
905 +       u32     celog1_add;
906 +       u32     celog2_add;
907 +       u16     celog1_syndrome;
908 +       u16     celog2_syndrome;
909 +       u32     retry_add;
910 +       u32     uelog_add;
911 +       u32     uelogs_add;
912 +       struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
913 +       struct pci_dev *pres_dev;
914 +        struct pci_dev *dev;
915 +
916 +       /* clear snapshot */
917 +       hi_ferr=hi_nerr=buf_ferr=buf_nerr=0;
918 +       sysbus_ferr=sysbus_nerr=dram_ferr=dram_nerr=0;
919 +       celog1_syndrome=celog2_syndrome=retry_add=0;
920 +       celog1_add=celog2_add=uelog_add=uelogs_add=0;
921 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
922 +
923 +       if (pvt->dev_d0f1 != NULL) {
924 +               dev = pvt->dev_d0f1;
925 +               pci_read_config_dword(dev,E752X_FERR_GLOBAL,&stat32);
926 +               if(stat32) { /* Error, so process */
927 +#if 1                  
928 +                       /* dump d0f0 and d0f1 */
929 +                       printk("\nDevice 0 Function 0");
930 +                       for(i=0;i<0x100;i++) {
931 +                               pci_read_config_byte(mci->pdev,i,&stat8);
932 +                               if((i%16)==0) {
933 +                                       printk("\n%2.2x  ",i);
934 +                               }
935 +                               printk("%2.2x ",stat8);
936 +                       }
937 +                       printk("\n");
938 +                       /* dump d0f0 and d0f1 */
939 +                       printk("\nDevice 0 Function 1");
940 +                       for(i=0;i<0x100;i++) {
941 +                               pci_read_config_byte(dev,i,&stat8);
942 +                               if((i%16)==0) {
943 +                                       printk("\n%2.2x  ",i);
944 +                               }
945 +                       printk("%2.2x ",stat8);
946 +                       }
947 +                       printk("\n\n");
948 +#endif                 
949 +                       /* take a snap shot of first errors */
950 +                       pci_read_config_byte(dev,E752X_HI_FERR,&hi_ferr);
951 +                       pci_read_config_word(dev,E752X_SYSBUS_FERR,&sysbus_ferr);
952 +                       pci_read_config_byte(dev,E752X_BUF_FERR,&buf_ferr);
953 +                       pci_read_config_word(dev,E752X_DRAM_FERR,&dram_ferr);
954 +                       pci_read_config_dword(dev,E752X_DRAM_CELOG1_ADD,
955 +                                       &celog1_add);
956 +                       pci_read_config_word(dev,E752X_DRAM_CELOG1_SYNDROME,
957 +                                       &celog1_syndrome);
958 +                       pci_read_config_dword(dev,E752X_DRAM_UELOG_ADD,
959 +                                       &uelog_add);
960 +                       pci_read_config_dword(dev,E752X_DRAM_UELOGS_ADD,
961 +                                       &uelogs_add);
962 +                       pci_read_config_dword(dev,E752X_DRAM_RETRY_ADD,
963 +                                       &retry_add);
964 +                       
965 +                       pci_write_config_dword(dev,E752X_FERR_GLOBAL,stat32);
966 +                       error32=(stat32>>18)&0x3ff;
967 +                       stat32=(stat32>>4)&0x7ff;
968 +                       if(error32) 
969 +                               global_error(1,error32);
970 +                       if(stat32)
971 +                               global_error(0,stat32);
972 +               }
973 +               
974 +               pci_read_config_dword(dev,E752X_NERR_GLOBAL,&stat32);
975 +               if(stat32) { /* Error, so process */
976 +                       /* take a snap shot of second errors */
977 +                       pci_read_config_byte(dev,E752X_HI_NERR,&hi_nerr);
978 +                       pci_read_config_word(dev,E752X_SYSBUS_NERR,&sysbus_nerr);
979 +                       pci_read_config_byte(dev,E752X_BUF_NERR,&buf_nerr);
980 +                       pci_read_config_word(dev,E752X_DRAM_NERR,&dram_nerr);
981 +                       pci_read_config_dword(dev,E752X_DRAM_CELOG2_ADD,
982 +                                       &celog2_add);
983 +                       pci_read_config_word(dev,E752X_DRAM_CELOG2_SYNDROME,
984 +                                       &celog2_syndrome);
985 +                       
986 +                       pci_write_config_dword(dev,E752X_NERR_GLOBAL,stat32);
987 +                       error32=(stat32>>18)&0x3ff;
988 +                       stat32=(stat32>>4)&0x7ff;
989 +                       if(error32) 
990 +                               global_error(1,error32);
991 +                       if(stat32)
992 +                               global_error(0,stat32);
993 +               }
994 +
995 +//             pci_read_config_byte(dev,E752X_HI_FERR,&stat8);
996 +               stat8=hi_ferr;
997 +               if(stat8&0x7f) { /* Error, so process */
998 +                       pci_write_config_dword(dev,E752X_HI_FERR,stat8);
999 +                       stat8 &= 0x7f;
1000 +                       if(stat8&0x2b) 
1001 +                               hub_error(1,(stat8&0x2b));
1002 +                       if(stat8 & 0x54)
1003 +                               hub_error(0,(stat8&0x54));
1004 +               }
1005 +//             pci_read_config_byte(dev,E752X_HI_NERR,&stat8);
1006 +               stat8=hi_nerr;
1007 +               if(stat8&0x7f) { /* Error, so process */
1008 +                       pci_write_config_dword(dev,E752X_HI_NERR,stat8);
1009 +                       stat8 &= 0x7f;
1010 +                       if(stat8&0x2b) 
1011 +                               hub_error(1,(stat8&0x2b));
1012 +                       if(stat8 & 0x54)
1013 +                               hub_error(0,(stat8&0x54));
1014 +               }
1015 +//             pci_read_config_dword(dev,E752X_SYSBUS_FERR,&stat32);
1016 +               stat32 = sysbus_ferr + (sysbus_nerr <<16);
1017 +               if(stat32) { /* Error, so process */
1018 +                       pci_write_config_dword(dev,E752X_SYSBUS_FERR,stat32);
1019 +                       error32=(stat32>>16)&0x3ff;
1020 +                       stat32=stat32&0x3ff;
1021 +                       if(stat32 & 0x083) 
1022 +                               sysbus_error(1,(stat32&0x083));
1023 +                       if(stat32 & 0x37c)
1024 +                               sysbus_error(0,(stat32&0x37c));
1025 +                       if(error32 & 0x083) 
1026 +                               sysbus_error(1,(error32&0x083));
1027 +                       if(error32 & 0x37c)
1028 +                               sysbus_error(0,(error32&0x37c));
1029 +               }
1030 +//             pci_read_config_byte(dev,E752X_BUF_FERR,&stat8);
1031 +               stat8 = buf_ferr;
1032 +               if(stat8&0x0f) { /* Error, so process */
1033 +                       pci_write_config_dword(dev,E752X_BUF_FERR,stat8);
1034 +                       stat8 &= 0x0f;
1035 +                       membuf_error(stat8);
1036 +               }
1037 +//             pci_read_config_byte(dev,E752X_BUF_NERR,&stat8);
1038 +               stat8 = buf_nerr;
1039 +               if(stat8&0x0f) { /* Error, so process */
1040 +                       pci_write_config_dword(dev,E752X_BUF_NERR,stat8);
1041 +                       stat8 &= 0x0f;
1042 +                       membuf_error(stat8);
1043 +               }
1044 +
1045 +
1046 +
1047 +               
1048 +//             pci_read_config_word(pvt->bridge_ck,E752X_DRAM_FERR,&error_one);
1049 +//             pci_read_config_word(pvt->bridge_ck,E752X_DRAM_NERR,&error_next);
1050 +               error_one = dram_ferr;
1051 +               error_next = dram_nerr;
1052 +               /* clear any error bits */
1053 +               if(error_one) {
1054 +                       pci_write_bits16(pvt->bridge_ck, E752X_DRAM_FERR, 
1055 +                                       error_one,error_one);
1056 +               }
1057 +               if(error_next) {
1058 +                       pci_write_bits16(pvt->bridge_ck, E752X_DRAM_NERR, 
1059 +                                       error_next, error_next);
1060 +               }
1061 +       
1062 +               /* decode and report errors */
1063 +               if(error_one & 0x0101) { /* check first error correctable */
1064 +                       process_ce(mci,error_one,celog1_add,celog1_syndrome);
1065 +               }
1066 +               if(error_next & 0x0101) { /* check next error correctable */
1067 +                       process_ce(mci,error_next,celog2_add,celog2_syndrome);
1068 +               }
1069 +               if(error_one & 0x4040) {
1070 +                       process_ue_no_info_wr(mci);
1071 +               }
1072 +               if(error_next & 0x4040) {
1073 +                       process_ue_no_info_wr(mci);
1074 +               }
1075 +               if(error_one & 0x2020) {
1076 +                       process_ded_retry(mci,error_one,retry_add);
1077 +               }
1078 +               if(error_next & 0x2020) {
1079 +                       process_ded_retry(mci,error_next,retry_add);
1080 +               }
1081 +               if(error_one & 0x0808) {
1082 +                       process_threshold_ce(mci,error_one);
1083 +               }
1084 +               if(error_next & 0x0808) {
1085 +                       process_threshold_ce(mci,error_next);
1086 +               }
1087 +               if(error_one & 0x0606) {
1088 +                       process_ue(mci,error_one,uelog_add,uelogs_add);
1089 +               }
1090 +               if(error_next & 0x0606) {
1091 +                       process_ue(mci,error_next,uelog_add,uelogs_add);
1092 +               }
1093 +               
1094 +
1095 +       }
1096 +       /* Test for PCI Parity errors in the southbridge */
1097 +       if (pvt->dev_d0f0 != NULL) {
1098 +               dev = pvt->dev_d0f0;
1099 +               for(pres_dev = dev;
1100 +                 ((struct pci_dev*)pres_dev->global_list.next != dev);
1101 +                 pres_dev = (struct pci_dev*)pres_dev->global_list.next) {
1102 +                       pci_read_config_dword(pres_dev,PCI_COMMAND,&stat32);
1103 +                       stat = (u16)(stat32 >>16);
1104 +                       /* test for error any error bits */
1105 +                       if(stat32 & ((1<<6)+(1<<8))) { /* error reporting dev */
1106 +                               if(stat & ((1<<15)+(1<<14)+(1<<8))) {
1107 +                                   pci_write_config_word(pres_dev,6,stat);
1108 +                                   if(stat & (1<<14)) {
1109 +                                     printk( KERN_WARNING
1110 +                                       "System Error on %s %s\n",
1111 +                                       pres_dev->slot_name,
1112 +                                       pci_pretty_name(pres_dev));
1113 +                                   }
1114 +                                   if(stat & ((1<<15)+(1<<8))) {
1115 +                                     printk( KERN_WARNING
1116 +                                       "Parity Error on %s %s\n",
1117 +                                       pres_dev->slot_name,
1118 +                                       pci_pretty_name(pres_dev));
1119 +                                   }
1120 +                               }
1121 +                       }
1122 +               }
1123 +       }
1124 +}
1125 +
1126 +
1127 +static int e752x_probe1( struct pci_dev *pdev, int dev_idx )
1128 +{
1129 +       int rc = -ENODEV;
1130 +       int index;
1131 +       u16 pci_data, stat;
1132 +       u32 stat32;
1133 +       u16 stat16;
1134 +       u8  stat8;
1135 +       struct mem_ctl_info *mci = NULL;
1136 +       struct e752x_pvt *pvt = NULL;
1137 +       u16 ddrcsr;
1138 +       u32 drc;
1139 +       int drc_chan;           /* Number of channels 0=1chan,1=2chan */
1140 +       int drc_drbg;           /* DRB granularity 0=32mb,1=64mb */
1141 +       int drc_ddim;           /* DRAM Data Integrity Mode 0=none,2=edac */
1142 +       u32 dra;
1143 +       unsigned long last_cumul_size;
1144 +       struct pci_dev *pres_dev;
1145 +        struct pci_dev *dev;
1146 +
1147 +       debugf0( "MC: " __FILE__ ": %s(): mci\n", __func__ );
1148 +  printk( KERN_ERR "Starting Probe1\n" );
1149 +
1150 +       /* enable device 0 function 1 */
1151 +       pci_read_config_byte(pdev, E752X_DEVPRES1, &stat8);
1152 +       stat8 |= (1<<5);
1153 +       pci_write_config_byte(pdev, E752X_DEVPRES1, stat8);
1154 +
1155 +       /* need to find out the number of channels */
1156 +       pci_read_config_dword(pdev, E752X_DRC, &drc);
1157 +       pci_read_config_word(pdev, E752X_DDRCSR, &ddrcsr);
1158 +       if(((ddrcsr>>12)&3)==3)
1159 +               drc_chan = 1;  /* Dual channel */
1160 +       else
1161 +               drc_chan = 0; /* Single channel */
1162 +       drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */ 
1163 +       drc_ddim = ( drc >> 20 ) & 0x3;
1164 +
1165 +       mci = bluesmoke_mc_init_structs(sizeof(*pvt),
1166 +                                       E752X_NR_CSROWS,
1167 +                                       drc_chan + 1);
1168 +
1169 +       if ( ! mci ) {
1170 +               rc = -ENOMEM;
1171 +               goto FAIL_FINISHED;
1172 +       }
1173 +
1174 +       debugf3( "MC: " __FILE__ ": %s(): init mci\n", __func__ );
1175 +
1176 +       mci->mtype_cap = MEM_FLAG_RDDR;
1177 +       mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_S4ECD4ED;
1178 +       /* FIXME - what if different memory types are in different csrows? */
1179 +       mci->mod_name = BS_MOD_STR;
1180 +       mci->mod_ver = "$Revision: 1.5 $";
1181 +       mci->pdev = pdev;
1182 +
1183 +       debugf3( "MC: " __FILE__ ": %s(): init pvt\n", __func__ );
1184 +       pvt = (struct e752x_pvt *)mci->pvt_info;
1185 +       pvt->dev_info = &e752x_devs[dev_idx];
1186 +       pvt->bridge_ck = pci_find_device( PCI_VENDOR_ID_INTEL,
1187 +                                         pvt->dev_info->err_dev,
1188 +                                         pvt->bridge_ck );
1189 +       if ( ! pvt->bridge_ck ) {
1190 +               pvt->bridge_ck = pci_scan_single_device(pdev->bus, PCI_DEVFN(0,1));
1191 +       }
1192 +       if ( ! pvt->bridge_ck ) {
1193 +               printk( KERN_ERR
1194 +                       "MC: error reporting device not found:"
1195 +                       "vendor %x device 0x%x (broken BIOS?)\n",
1196 +                       PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev );
1197 +               goto FAIL_FINISHED;
1198 +       }
1199 +       if(ddrcsr & 0x10) {
1200 +               pvt->mc_symmetric = 1;
1201 +       } else {
1202 +               pvt->mc_symmetric =0;
1203 +       }
1204 +
1205 +       debugf3( "MC: " __FILE__ ": %s(): more mci init\n", __func__ );
1206 +       mci->ctl_name = pvt->dev_info->ctl_name;
1207 +
1208 +       mci->edac_check = e752x_check;
1209 +       /* FIXME - why isn't clear_err set to something? */
1210 +       mci->clear_err = NULL;
1211 +       mci->ctl_page_to_phys = ctl_page_to_phys;
1212 +
1213 +       /* find out the device types */
1214 +       pci_read_config_dword(pdev, E752X_DRA, &dra);
1215 +
1216 +       /*
1217 +        * The dram row boundary (DRB) reg values are boundary address
1218 +        * for each DRAM row with a granularity of 64 or 128MB (single/dual
1219 +        * channel operation).  DRB regs are cumulative; therefore DRB7 will
1220 +        * contain the total memory contained in all eight rows.
1221 +        */
1222 +       for( last_cumul_size = index = 0; index < mci->nr_csrows; index++ ) {
1223 +               u8 value;
1224 +               u32 cumul_size;
1225 +               /* mem_dev 0=x8, 1=x4 */
1226 +               int mem_dev = ( dra >> ( index * 4 + 2 ) ) & 0x3;
1227 +               struct csrow_info *csrow = &mci->csrows[ index ];
1228 +
1229 +               if(mem_dev == 2)
1230 +                       mem_dev = 1;
1231 +               else
1232 +                       mem_dev = 0;
1233 +               pci_read_config_byte(mci->pdev, E752X_DRB + index, &value);
1234 +               /* convert a 128 or 64 MiB DRB to a page size. */
1235 +               cumul_size = value << (25 + drc_drbg - PAGE_SHIFT );
1236 +               debugf3( "MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n",
1237 +                       __func__, index, cumul_size );
1238 +               if ( cumul_size == last_cumul_size ) {
1239 +                       continue;       /* not populated */
1240 +               }
1241 +
1242 +               csrow->first_page = last_cumul_size;
1243 +               csrow->last_page = cumul_size - 1;
1244 +               csrow->nr_pages = cumul_size - last_cumul_size;
1245 +               last_cumul_size = cumul_size;
1246 +               csrow->grain = 1 << 12;         /* 4KiB - resolution of CELOG */
1247 +               csrow->mtype = MEM_RDDR;        /* only one type supported */
1248 +               csrow->dtype = mem_dev ? DEV_X4 : DEV_X8;
1249 +
1250 +               /*
1251 +                * if single channel or x8 devices then SECDED
1252 +                * if dual channel and x4 then S4ECD4ED
1253 +                */
1254 +               if ( drc_ddim ) {
1255 +                       if ( drc_chan && mem_dev ) {
1256 +                               csrow->edac_mode = EDAC_S4ECD4ED;
1257 +                               mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
1258 +                       } else {
1259 +                               csrow->edac_mode = EDAC_SECDED;
1260 +                               mci->edac_cap |= EDAC_FLAG_SECDED;
1261 +                       }
1262 +               } else {
1263 +                       csrow->edac_mode = EDAC_NONE;
1264 +               }
1265 +       }
1266 +       
1267 +       /* Fill in the memory map table */
1268 +       {
1269 +               u8 value;
1270 +               u8 last=0;
1271 +               u8 row=0;
1272 +       for(index=0;index<8;index+=2) {
1273 +               
1274 +               pci_read_config_byte(mci->pdev, E752X_DRB + index, &value);
1275 +               /* test if there is a dimm in this slot */
1276 +               if(value == last) {
1277 +                       /* no dimm in the slot, so flag it as empty */
1278 +                       pvt->map[index]=0xff;
1279 +                       pvt->map[index+1]=0xff;
1280 +               }
1281 +               else {  /* there is a dimm in the slot */
1282 +                       pvt->map[index]=row;
1283 +                       row++;
1284 +                       last = value;
1285 +                       /* test the next value to see if the dimm is double sided */
1286 +                       pci_read_config_byte(mci->pdev, E752X_DRB + index + 1, &value);
1287 +                       if(value == last) {
1288 +                               /* the dimm is single sided, so flag as empty */
1289 +                               pvt->map[index+1]=0xff;
1290 +                               row++;
1291 +                       }
1292 +                       else {
1293 +                               /* this is a double sided dimm to save the next row # */
1294 +                               pvt->map[index+1]=row;
1295 +                               row++;
1296 +                       }
1297 +                       last = value;
1298 +               }
1299 +       }
1300 +       }
1301 +
1302 +       /* set the map type.  1 = normal, 0 = reversed */
1303 +       pci_read_config_byte(mci->pdev, E752X_DRM, &stat8);
1304 +       if((stat8&0x0f) > ((stat8>>4)&0x0f)) {
1305 +               /* map type is normal */
1306 +               pvt->map_type = 1;
1307 +       }
1308 +       else {
1309 +               /* map type is reversed */
1310 +               pvt->map_type = 0;
1311 +       }
1312 +
1313 +       mci->edac_cap |= EDAC_FLAG_NONE;
1314 +
1315 +       debugf3( "MC: " __FILE__ ": %s(): tolm, remapbase, remaplimit\n", __func__ );
1316 +       /* load the top of low memory, remap base, and remap limit vars */
1317 +       pci_read_config_word(mci->pdev, E752X_TOLM, &pci_data);
1318 +       pvt->tolm = ((u32)pci_data) << 4;
1319 +       pci_read_config_word(mci->pdev, E752X_REMAPBASE, &pci_data);
1320 +       pvt->remapbase = ((u32)pci_data) << 14;
1321 +       pci_read_config_word(mci->pdev, E752X_REMAPLIMIT, &pci_data);
1322 +       pvt->remaplimit = ((u32)pci_data) << 14;
1323 +       printk( "tolm = %x, remapbase = %x, remaplimit = %x\n",
1324 +               pvt->tolm, pvt->remapbase, pvt->remaplimit);
1325 +
1326 +       if ( 0 != bluesmoke_mc_add_mc( mci ) ) {
1327 +               debugf3( "MC: " __FILE__ ": %s(): failed bluesmoke_mc_add_mc()\n", __func__ );
1328 +               goto FAIL_FINISHED;
1329 +       }
1330 +
1331 +       /* Walk through the PCI table and clear errors */       
1332 +       dev = pci_find_device( PCI_VENDOR_ID_INTEL,
1333 +                  PCI_DEVICE_ID_INTEL_7520_0, NULL );
1334 +       pvt->dev_d0f0 = dev;
1335 +        for(pres_dev = dev;
1336 +                 ((struct pci_dev*)pres_dev->global_list.next != dev);
1337 +                 pres_dev = (struct pci_dev*)pres_dev->global_list.next) {
1338 +               pci_read_config_dword(pres_dev,PCI_COMMAND,&stat32);
1339 +               stat = (u16)(stat32 >>16);
1340 +               /* clear any error bits */
1341 +               if(stat32 & ((1<<6)+(1<<8))) {
1342 +                       pci_write_config_word(pres_dev,PCI_STATUS,stat);
1343 +               }
1344 +       }
1345 +       /* find the error reporting device and clear errors */
1346 +       dev = pvt->dev_d0f1 = pvt->bridge_ck;
1347 +       /* Turn off error disable & SMI in case the BIOS turned it on */
1348 +       pci_write_config_byte(dev,E752X_HI_ERRMASK,0x00);
1349 +       pci_write_config_byte(dev,E752X_HI_SMICMD,0x00);
1350 +       pci_write_config_word(dev,E752X_SYSBUS_ERRMASK,0x00);
1351 +       pci_write_config_word(dev,E752X_SYSBUS_SMICMD,0x00);
1352 +       pci_write_config_byte(dev,E752X_BUF_ERRMASK,0x00);
1353 +       pci_write_config_byte(dev,E752X_BUF_SMICMD,0x00);
1354 +       pci_write_config_byte(dev,E752X_DRAM_ERRMASK,0x00);
1355 +       pci_write_config_byte(dev,E752X_DRAM_SMICMD,0x00);
1356 +       /* clear other MCH errors */
1357 +       pci_read_config_dword(dev,E752X_FERR_GLOBAL,&stat32);
1358 +       pci_write_config_dword(dev,E752X_FERR_GLOBAL,stat32);
1359 +       pci_read_config_dword(dev,E752X_NERR_GLOBAL,&stat32);
1360 +       pci_write_config_dword(dev,E752X_NERR_GLOBAL,stat32);
1361 +       pci_read_config_byte(dev,E752X_HI_FERR,&stat8);
1362 +       pci_write_config_byte(dev,E752X_HI_FERR,stat8);
1363 +       pci_read_config_byte(dev,E752X_HI_NERR,&stat8);
1364 +       pci_write_config_byte(dev,E752X_HI_NERR,stat8);
1365 +       pci_read_config_dword(dev,E752X_SYSBUS_FERR,&stat32);
1366 +       pci_write_config_dword(dev,E752X_SYSBUS_FERR,stat32);
1367 +       pci_read_config_byte(dev,E752X_BUF_FERR,&stat8);
1368 +       pci_write_config_byte(dev,E752X_BUF_FERR,stat8);
1369 +       pci_read_config_byte(dev,E752X_BUF_NERR,&stat8);
1370 +       pci_write_config_byte(dev,E752X_BUF_NERR,stat8);
1371 +       pci_read_config_word(dev, E752X_DRAM_FERR, &stat16);
1372 +       pci_write_config_word(dev, E752X_DRAM_FERR, stat16);
1373 +       pci_read_config_word(dev, E752X_DRAM_NERR, &stat16);
1374 +       pci_write_config_word(dev, E752X_DRAM_NERR, stat16);
1375 +       
1376 +       /* get this far and it's successful */
1377 +       debugf3( "MC: " __FILE__ ": %s(): success\n", __func__ );
1378 +       rc = 0;
1379 +       goto FINISHED;
1380 +
1381 + FAIL_FINISHED:
1382 +       if ( mci ) {
1383 +               kfree( mci );
1384 +       }
1385 + FINISHED:
1386 +       return( rc );
1387 +}
1388 +
1389 +
1390 +#ifdef CONFIG_PM
1391 +
1392 +static int e752x_suspend (struct pci_dev *pdev, u32 state)
1393 +{
1394 +       debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
1395 +
1396 +       return -ENOSYS;
1397 +}
1398 +
1399 +
1400 +static int e752x_resume (struct pci_dev *pdev)
1401 +{
1402 +       debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
1403 +
1404 +       return -ENOSYS;
1405 +}
1406 +
1407 +#endif /* CONFIG_PM */
1408 +
1409 +
1410 +/* returns count (>= 0), or negative on error */
1411 +static int __devinit e752x_init_one( struct pci_dev *pdev,
1412 +                                    const struct pci_device_id *ent )
1413 +{
1414 +       int rc;
1415 +
1416 +       debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
1417 +
1418 +       /* wake up and enable device */         
1419 +       if (pci_enable_device (pdev)) {
1420 +               rc = -EIO;
1421 +       } else {
1422 +               rc = e752x_probe1( pdev, ent->driver_data );
1423 +       }
1424 +       return rc;
1425 +}
1426 +
1427 +
1428 +static void __devexit e752x_remove_one( struct pci_dev *pdev )
1429 +{
1430 +       struct mem_ctl_info *mci;
1431 +
1432 +       debugf0( __FILE__ ": %s()\n", __func__);
1433 +
1434 +       if ( NULL == ( mci = bluesmoke_mc_find_mci_by_pdev( pdev ) ) ) {
1435 +               goto FINISHED;
1436 +       }
1437 +
1438 +       if ( 0 != bluesmoke_mc_del_mc( mci ) ) {
1439 +               goto FINISHED;
1440 +       }
1441 +
1442 +       kfree( mci );
1443 +
1444 + FINISHED:
1445 +       return;
1446 +}
1447 +
1448 +
1449 +static const struct pci_device_id e752x_pci_tbl[] __devinitdata = {
1450 +       { PCI_VEND_DEV( INTEL, 7520_0 ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, E7520 },
1451 +       {0,}                                            /* 0 terminated list. */
1452 +};
1453 +
1454 +MODULE_DEVICE_TABLE(pci, e752x_pci_tbl);
1455 +
1456 +
1457 +static struct pci_driver e752x_driver = {
1458 +       name:           BS_MOD_STR,
1459 +       probe:          e752x_init_one,
1460 +       remove:         __devexit_p(e752x_remove_one),
1461 +       id_table:       e752x_pci_tbl,
1462 +#ifdef CONFIG_PM
1463 +       suspend:        e752x_suspend,
1464 +       resume:         e752x_resume,
1465 +#endif /* CONFIG_PM */
1466 +};
1467 +
1468 +
1469 +int __init e752x_init(void)
1470 +{
1471 +       int pci_rc;
1472 +
1473 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
1474 +       pci_rc = pci_module_init( &e752x_driver );
1475 +       if ( pci_rc < 0 ) return pci_rc;
1476 +
1477 +       return 0;
1478 +}
1479 +
1480 +
1481 +static void __exit e752x_exit(void)
1482 +{
1483 +       debugf3( "MC: "  __FILE__ ": %s()\n", __func__ );
1484 +       pci_unregister_driver( &e752x_driver );
1485 +}
1486 +
1487 +
1488 +module_init(e752x_init);
1489 +module_exit(e752x_exit);
1490 +
1491 +MODULE_LICENSE("GPL");
1492 +MODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman\n");
1493 +MODULE_DESCRIPTION("MC support for Intel e752x memory controllers");
1494 Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_e7xxx.c
1495 ===================================================================
1496 --- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/bluesmoke_e7xxx.c      1969-12-31 19:00:00.000000000 -0500
1497 +++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_e7xxx.c   2004-12-17 12:46:23.000000000 -0500
1498 @@ -0,0 +1,552 @@
1499 +/*
1500 + * Intel e7xxx Memory Controller kernel module
1501 + * (C) 2003 Linux Networx (http://lnxi.com)
1502 + * This file may be distributed under the terms of the
1503 + * GNU General Public License.
1504 + *
1505 + * See "enum e7xxx_chips" below for supported chipsets
1506 + *
1507 + * Written by Thayne Harbaugh
1508 + * Based on work by Dan Hollis <goemon at anime dot net> and others.
1509 + *     http://www.anime.net/~goemon/linux-ecc/
1510 + *
1511 + * Contributors:
1512 + *     Eric Biederman (Linux Networx)
1513 + *     Tom Zimmerman (Linux Networx)
1514 + *     Jim Garlic (Lawrence Livermore National Labs)
1515 + *     Dave Peterson (Lawrence Livermore National Labs)
1516 + *     That One Guy (Some other place)
1517 + *
1518 + * $Id: bluesmoke_e7xxx.c,v 1.5 2004/11/18 22:19:46 thayne Exp $
1519 + *
1520 + */
1521 +
1522 +
1523 +#include <linux/config.h>
1524 +#include <linux/module.h>
1525 +#include <linux/init.h>
1526 +
1527 +#include <linux/pci.h>
1528 +#include <linux/pci_ids.h>
1529 +
1530 +#include <linux/slab.h>
1531 +
1532 +#include "bluesmoke_mc.h"
1533 +
1534 +
1535 +#ifndef PCI_DEVICE_ID_INTEL_7205_0
1536 +#define PCI_DEVICE_ID_INTEL_7205_0     0x255d
1537 +#endif /* PCI_DEVICE_ID_INTEL_7205_0 */
1538 +
1539 +#ifndef PCI_DEVICE_ID_INTEL_7205_1_ERR
1540 +#define PCI_DEVICE_ID_INTEL_7205_1_ERR 0x2551
1541 +#endif /* PCI_DEVICE_ID_INTEL_7205_1_ERR */
1542 +
1543 +#ifndef PCI_DEVICE_ID_INTEL_7500_0
1544 +#define PCI_DEVICE_ID_INTEL_7500_0     0x2540
1545 +#endif /* PCI_DEVICE_ID_INTEL_7500_0 */
1546 +
1547 +#ifndef PCI_DEVICE_ID_INTEL_7500_1_ERR
1548 +#define PCI_DEVICE_ID_INTEL_7500_1_ERR 0x2541
1549 +#endif /* PCI_DEVICE_ID_INTEL_7500_1_ERR */
1550 +
1551 +#ifndef PCI_DEVICE_ID_INTEL_7501_0
1552 +#define PCI_DEVICE_ID_INTEL_7501_0     0x254c
1553 +#endif /* PCI_DEVICE_ID_INTEL_7501_0 */
1554 +
1555 +#ifndef PCI_DEVICE_ID_INTEL_7501_1_ERR
1556 +#define PCI_DEVICE_ID_INTEL_7501_1_ERR 0x2541
1557 +#endif /* PCI_DEVICE_ID_INTEL_7501_1_ERR */
1558 +
1559 +#ifndef PCI_DEVICE_ID_INTEL_7505_0
1560 +#define PCI_DEVICE_ID_INTEL_7505_0     0x2550
1561 +#endif /* PCI_DEVICE_ID_INTEL_7505_0 */
1562 +
1563 +#ifndef PCI_DEVICE_ID_INTEL_7505_1_ERR
1564 +#define PCI_DEVICE_ID_INTEL_7505_1_ERR 0x2551
1565 +#endif /* PCI_DEVICE_ID_INTEL_7505_1_ERR */
1566 +
1567 +
1568 +#define E7XXX_NR_CSROWS                8       /* number of csrows */
1569 +#define E7XXX_NR_DIMMS         8       /* FIXME - is this correct? */
1570 +
1571 +
1572 +/* E7XXX register addresses - device 0 function 0 */
1573 +#define E7XXX_DRB              0x60    /* DRAM row boundary register (8b) */
1574 +#define E7XXX_DRA              0x70    /* DRAM row attribute register (8b) */
1575 +                                       /*
1576 +                                        * 31   Device width row 7 0=x8 1=x4
1577 +                                        * 27   Device width row 6
1578 +                                        * 23   Device width row 5
1579 +                                        * 19   Device width row 4
1580 +                                        * 15   Device width row 3
1581 +                                        * 11   Device width row 2
1582 +                                        *  7   Device width row 1
1583 +                                        *  3   Device width row 0
1584 +                                        */
1585 +#define E7XXX_DRC              0x7C    /* DRAM controller mode reg (32b) */
1586 +                                       /*
1587 +                                        * 22    Number channels 0=1,1=2
1588 +                                        * 19:18 DRB Granularity 32/64MB
1589 +                                        */
1590 +#define E7XXX_TOLM             0xC4    /* DRAM top of low memory reg (16b) */
1591 +#define E7XXX_REMAPBASE                0xC6    /* DRAM remap base address reg (16b) */
1592 +#define E7XXX_REMAPLIMIT       0xC8    /* DRAM remap limit address reg (16b) */
1593 +
1594 +/* E7XXX register addresses - device 0 function 1 */
1595 +#define E7XXX_DRAM_FERR                0x80    /* DRAM first error register (8b) */
1596 +#define E7XXX_DRAM_NERR                0x82    /* DRAM next error register (8b) */
1597 +#define E7XXX_DRAM_CELOG_ADD   0xA0    /* DRAM first correctable memory */
1598 +                                       /*     error address register (32b) */
1599 +                                       /*
1600 +                                        * 31:28 Reserved
1601 +                                        * 27:6  CE address (4k block 33:12)
1602 +                                        *  5:0  Reserved
1603 +                                        */
1604 +#define E7XXX_DRAM_UELOG_ADD   0xB0    /* DRAM first uncorrectable memory */
1605 +                                       /*     error address register (32b) */
1606 +                                       /*
1607 +                                        * 31:28 Reserved
1608 +                                        * 27:6  CE address (4k block 33:12)
1609 +                                        *  5:0  Reserved
1610 +                                        */
1611 +#define E7XXX_DRAM_CELOG_SYNDROME 0xD0 /* DRAM first correctable memory */
1612 +                                       /*     error syndrome register (16b) */
1613 +
1614 +enum e7xxx_chips {
1615 +       E7500 = 0,
1616 +       E7501,
1617 +       E7505,
1618 +       E7205,
1619 +};
1620 +
1621 +
1622 +struct e7xxx_pvt {
1623 +       struct pci_dev *bridge_ck;
1624 +       u32 tolm;
1625 +       u32 remapbase;
1626 +       u32 remaplimit;
1627 +       const struct e7xxx_dev_info *dev_info;
1628 +};
1629 +
1630 +
1631 +struct e7xxx_dev_info {
1632 +       u16 err_dev;
1633 +       const char *ctl_name;
1634 +};
1635 +
1636 +
1637 +static const struct e7xxx_dev_info e7xxx_devs[] = {
1638 +       [E7500] = {
1639 +               .err_dev  = PCI_DEVICE_ID_INTEL_7500_1_ERR,
1640 +               .ctl_name = "E7500"
1641 +       },
1642 +       [E7501] = {
1643 +               .err_dev  = PCI_DEVICE_ID_INTEL_7501_1_ERR,
1644 +               .ctl_name = "E7501"
1645 +       },
1646 +       [E7505] = {
1647 +               .err_dev  = PCI_DEVICE_ID_INTEL_7505_1_ERR,
1648 +               .ctl_name = "E7505"
1649 +       },
1650 +       [E7205] = {
1651 +               .err_dev  = PCI_DEVICE_ID_INTEL_7205_1_ERR,
1652 +               .ctl_name = "E7205"
1653 +       },
1654 +};
1655 +
1656 +
1657 +/* FIXME - is this valid for both SECDED and S4ECD4ED? */
1658 +static inline int e7xxx_find_channel(u16 syndrome)
1659 +{
1660 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
1661 +
1662 +       if((syndrome & 0xff00)==0)
1663 +               return(0);
1664 +       if((syndrome & 0x00ff)==0)
1665 +               return(1);
1666 +       if((syndrome & 0xf000)==0)
1667 +               return(0);
1668 +       if((syndrome & 0x0f00)==0)
1669 +               return(0);
1670 +       return(1);
1671 +}
1672 +
1673 +
1674 +static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
1675 +                                     unsigned long page)
1676 +{
1677 +       u32 remap;
1678 +       struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info;
1679 +
1680 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
1681 +
1682 +       if(page < pvt->tolm)
1683 +               return(page);
1684 +       if((page >= 0x100000)&&(page < pvt->remapbase))
1685 +               return(page);
1686 +       remap = (page - pvt->tolm) + pvt->remapbase;
1687 +       if(remap < pvt->remaplimit)
1688 +               return(remap);  
1689 +       printk(KERN_ERR "Invalid page %lx - out of range\n", page);
1690 +       return(pvt->tolm-1);
1691 +}
1692 +
1693 +
1694 +static void process_ce(struct mem_ctl_info *mci)
1695 +{
1696 +       u32 error_1b, page;
1697 +       u16 syndrome;
1698 +       int row;
1699 +       int channel;
1700 +       struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info;
1701 +
1702 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
1703 +
1704 +       /* read the error address */
1705 +       pci_read_config_dword(pvt->bridge_ck,E7XXX_DRAM_CELOG_ADD,
1706 +                               &error_1b);
1707 +       /* FIXME - should use PAGE_SHIFT */
1708 +       page = error_1b >>6;  /* convert the address to 4k page */
1709 +       /* read the syndrome */
1710 +       pci_read_config_word(pvt->bridge_ck,E7XXX_DRAM_CELOG_SYNDROME,
1711 +                       &syndrome);
1712 +       /* FIXME - check for -1 */
1713 +       row = bluesmoke_mc_find_csrow_by_page( mci, page );
1714 +       channel = e7xxx_find_channel(syndrome); /* convert syndrome to channel */
1715 +       bluesmoke_mc_handle_ce( mci, page, 0, syndrome,
1716 +                               row, channel, "e7xxx CE" );
1717 +}
1718 +
1719 +
1720 +static void process_ce_no_info(struct mem_ctl_info *mci)
1721 +{
1722 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
1723 +
1724 +       bluesmoke_mc_handle_ce_no_info( mci, "e7xxx CE log register overflow" );
1725 +}
1726 +
1727 +
1728 +static void process_ue(struct mem_ctl_info *mci)
1729 +{
1730 +       u32 error_2b, block_page;
1731 +       int row;
1732 +       struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info;
1733 +
1734 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
1735 +
1736 +       /* read the error address */
1737 +       pci_read_config_dword( pvt->bridge_ck, E7XXX_DRAM_UELOG_ADD,
1738 +                              &error_2b );
1739 +       /* FIXME - should use PAGE_SHIFT */
1740 +       block_page = error_2b >>6;  /* convert to 4k address */
1741 +       row = bluesmoke_mc_find_csrow_by_page( mci, block_page );
1742 +       bluesmoke_mc_handle_ue( mci, block_page, 0, row, "e7xxx UE" );
1743 +}
1744 +
1745 +
1746 +static void process_ue_no_info(struct mem_ctl_info *mci)
1747 +{
1748 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
1749 +
1750 +       bluesmoke_mc_handle_ue_no_info( mci, "e7xxx UE log register overflow" );
1751 +}
1752 +
1753 +
1754 +static void e7xxx_check(struct mem_ctl_info *mci)
1755 +{
1756 +       u8  error_one, error_next;
1757 +       struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info;
1758 +
1759 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
1760 +
1761 +       pci_read_config_byte(pvt->bridge_ck,E7XXX_DRAM_FERR,&error_one);
1762 +       pci_read_config_byte(pvt->bridge_ck,E7XXX_DRAM_NERR,&error_next);
1763 +
1764 +       /* clear any error bits */
1765 +       if(error_one & 3) {
1766 +               pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_FERR, 0x03, 0x03);
1767 +       }
1768 +       if(error_next & 3) {
1769 +               pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03, 0x03);
1770 +       }
1771 +
1772 +       /* decode and report errors */
1773 +       if(error_one & 1) { /* check first error correctable */
1774 +               process_ce(mci);
1775 +               if(error_next & 1) {  /* check next error correctable */
1776 +                       process_ce_no_info(mci);
1777 +               }
1778 +               if(error_next & 2) {  /* check next error uncorrectable */
1779 +                       process_ue(mci);
1780 +               }
1781 +       } else if(error_one & 2) { /* check first error uncorrectable */
1782 +               process_ue(mci);
1783 +               if(error_next & 1) {  /* check next error correctable */
1784 +                       process_ce(mci);
1785 +               }
1786 +               if(error_next & 2) {  /* check next error uncorrectable */
1787 +                       process_ue_no_info(mci);
1788 +               }
1789 +       }
1790 +}
1791 +
1792 +
1793 +static int e7xxx_probe1( struct pci_dev *pdev, int dev_idx )
1794 +{
1795 +       int rc = -ENODEV;
1796 +       int index;
1797 +       u16 pci_data;
1798 +       struct mem_ctl_info *mci = NULL;
1799 +       struct e7xxx_pvt *pvt = NULL;
1800 +       u32 drc;
1801 +       int drc_chan;           /* Number of channels 0=1chan,1=2chan */
1802 +       int drc_drbg;           /* DRB granularity 0=32mb,1=64mb */
1803 +       int drc_ddim;           /* DRAM Data Integrity Mode 0=none,2=edac */
1804 +       u32 dra;
1805 +       unsigned long last_cumul_size;
1806 +       
1807 +
1808 +       debugf0( "MC: " __FILE__ ": %s(): mci\n", __func__ );
1809 +
1810 +       /* need to find out the number of channels */
1811 +       pci_read_config_dword(pdev, E7XXX_DRC, &drc);
1812 +       drc_chan = ( ( drc >> 22 ) & 0x1 );
1813 +       drc_drbg = ( drc >> 18 ) & 0x3;
1814 +       drc_ddim = ( drc >> 20 ) & 0x3;
1815 +
1816 +       mci = bluesmoke_mc_init_structs(sizeof(*pvt),
1817 +                                       E7XXX_NR_CSROWS,
1818 +                                       drc_chan + 1);
1819 +
1820 +       if ( ! mci ) {
1821 +               rc = -ENOMEM;
1822 +               goto FAIL_FINISHED;
1823 +       }
1824 +
1825 +       debugf3( "MC: " __FILE__ ": %s(): init mci\n", __func__ );
1826 +
1827 +       mci->mtype_cap = MEM_FLAG_RDDR;
1828 +       mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_S4ECD4ED;
1829 +       /* FIXME - what if different memory types are in different csrows? */
1830 +       mci->mod_name = BS_MOD_STR;
1831 +       mci->mod_ver = "$Revision: 1.5 $";
1832 +       mci->pdev = pdev;
1833 +
1834 +       debugf3( "MC: " __FILE__ ": %s(): init pvt\n", __func__ );
1835 +       pvt = (struct e7xxx_pvt *)mci->pvt_info;
1836 +       pvt->dev_info = &e7xxx_devs[dev_idx];
1837 +       pvt->bridge_ck = pci_find_device( PCI_VENDOR_ID_INTEL,
1838 +                                         pvt->dev_info->err_dev,
1839 +                                         pvt->bridge_ck );
1840 +       if ( ! pvt->bridge_ck ) {
1841 +               printk( KERN_ERR
1842 +                       "MC: error reporting device not found:"
1843 +                       "vendor %x device 0x%x (broken BIOS?)\n",
1844 +                       PCI_VENDOR_ID_INTEL, e7xxx_devs[dev_idx].err_dev );
1845 +               goto FAIL_FINISHED;
1846 +       }
1847 +
1848 +       debugf3( "MC: " __FILE__ ": %s(): more mci init\n", __func__ );
1849 +       mci->ctl_name = pvt->dev_info->ctl_name;
1850 +
1851 +       mci->edac_check = e7xxx_check;
1852 +       /* FIXME - why isn't clear_err set to something? */
1853 +       mci->clear_err = NULL;
1854 +       mci->ctl_page_to_phys = ctl_page_to_phys;
1855 +
1856 +       /* find out the device types */
1857 +       pci_read_config_dword(pdev, E7XXX_DRA, &dra);
1858 +
1859 +       /*
1860 +        * The dram row boundary (DRB) reg values are boundary address
1861 +        * for each DRAM row with a granularity of 32 or 64MB (single/dual
1862 +        * channel operation).  DRB regs are cumulative; therefore DRB7 will
1863 +        * contain the total memory contained in all eight rows.
1864 +        */
1865 +       for( last_cumul_size = index = 0; index < mci->nr_csrows; index++ ) {
1866 +               u8 value;
1867 +               u32 cumul_size;
1868 +               /* mem_dev 0=x8, 1=x4 */
1869 +               int mem_dev = ( dra >> ( index * 4 + 3 ) ) & 0x1;
1870 +               struct csrow_info *csrow = &mci->csrows[ index ];
1871 +
1872 +               pci_read_config_byte(mci->pdev, E7XXX_DRB + index, &value);
1873 +               /* convert a 64 or 32 MiB DRB to a page size. */
1874 +               cumul_size = value << (25 + drc_drbg - PAGE_SHIFT );
1875 +               debugf3( "MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n",
1876 +                       __func__, index, cumul_size );
1877 +               if ( cumul_size == last_cumul_size ) {
1878 +                       continue;       /* not populated */
1879 +               }
1880 +
1881 +               csrow->first_page = last_cumul_size;
1882 +               csrow->last_page = cumul_size - 1;
1883 +               csrow->nr_pages = cumul_size - last_cumul_size;
1884 +               last_cumul_size = cumul_size;
1885 +               csrow->grain = 1 << 12;         /* 4KiB - resolution of CELOG */
1886 +               csrow->mtype = MEM_RDDR;        /* only one type supported */
1887 +               csrow->dtype = mem_dev ? DEV_X4 : DEV_X8;
1888 +
1889 +               /*
1890 +                * if single channel or x8 devices then SECDED
1891 +                * if dual channel and x4 then S4ECD4ED
1892 +                */
1893 +               if ( drc_ddim ) {
1894 +                       if ( drc_chan && mem_dev ) {
1895 +                               csrow->edac_mode = EDAC_S4ECD4ED;
1896 +                               mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
1897 +                       } else {
1898 +                               csrow->edac_mode = EDAC_SECDED;
1899 +                               mci->edac_cap |= EDAC_FLAG_SECDED;
1900 +                       }
1901 +               } else {
1902 +                       csrow->edac_mode = EDAC_NONE;
1903 +               }
1904 +       }
1905 +
1906 +       mci->edac_cap |= EDAC_FLAG_NONE;
1907 +
1908 +       debugf3( "MC: " __FILE__ ": %s(): tolm, remapbase, remaplimit\n", __func__ );
1909 +       /* load the top of low memory, remap base, and remap limit vars */
1910 +       pci_read_config_word(mci->pdev, E7XXX_TOLM, &pci_data);
1911 +       pvt->tolm = ((u32)pci_data) << 4;
1912 +       pci_read_config_word(mci->pdev, E7XXX_REMAPBASE, &pci_data);
1913 +       pvt->remapbase = ((u32)pci_data) << 14;
1914 +       pci_read_config_word(mci->pdev, E7XXX_REMAPLIMIT, &pci_data);
1915 +       pvt->remaplimit = ((u32)pci_data) << 14;
1916 +       printk( "tolm = %x, remapbase = %x, remaplimit = %x\n",
1917 +               pvt->tolm, pvt->remapbase, pvt->remaplimit);
1918 +
1919 +       /* clear any pending errors, or initial state bits */
1920 +       pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_FERR, 0x03, 0x03);
1921 +       pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03, 0x03);
1922 +
1923 +       if ( 0 != bluesmoke_mc_add_mc( mci ) ) {
1924 +               debugf3( "MC: " __FILE__ ": %s(): failed bluesmoke_mc_add_mc()\n", __func__ );
1925 +               goto FAIL_FINISHED;
1926 +       }
1927 +
1928 +       /* get this far and it's successful */
1929 +       debugf3( "MC: " __FILE__ ": %s(): success\n", __func__ );
1930 +       rc = 0;
1931 +       goto FINISHED;
1932 +
1933 + FAIL_FINISHED:
1934 +       if ( mci ) {
1935 +               kfree( mci );
1936 +       }
1937 + FINISHED:
1938 +       return( rc );
1939 +}
1940 +
1941 +
1942 +#ifdef CONFIG_PM
1943 +
1944 +static int e7xxx_suspend (struct pci_dev *pdev, u32 state)
1945 +{
1946 +       debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
1947 +
1948 +       return -ENOSYS;
1949 +}
1950 +
1951 +
1952 +static int e7xxx_resume (struct pci_dev *pdev)
1953 +{
1954 +       debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
1955 +
1956 +       return -ENOSYS;
1957 +}
1958 +
1959 +#endif /* CONFIG_PM */
1960 +
1961 +
1962 +/* returns count (>= 0), or negative on error */
1963 +static int __devinit e7xxx_init_one( struct pci_dev *pdev,
1964 +                                    const struct pci_device_id *ent )
1965 +{
1966 +       int rc;
1967 +
1968 +       debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
1969 +
1970 +       /* wake up and enable device */         
1971 +       if (pci_enable_device (pdev)) {
1972 +               rc = -EIO;
1973 +       } else {
1974 +               rc = e7xxx_probe1( pdev, ent->driver_data );
1975 +       }
1976 +       return rc;
1977 +}
1978 +
1979 +
1980 +static void __devexit e7xxx_remove_one( struct pci_dev *pdev )
1981 +{
1982 +       struct mem_ctl_info *mci;
1983 +
1984 +       debugf0( __FILE__ ": %s()\n", __func__);
1985 +
1986 +       if ( NULL == ( mci = bluesmoke_mc_find_mci_by_pdev( pdev ) ) ) {
1987 +               goto FINISHED;
1988 +       }
1989 +
1990 +       if ( 0 != bluesmoke_mc_del_mc( mci ) ) {
1991 +               goto FINISHED;
1992 +       }
1993 +
1994 +       kfree( mci );
1995 +
1996 + FINISHED:
1997 +       return;
1998 +}
1999 +
2000 +
2001 +static const struct pci_device_id e7xxx_pci_tbl[] __devinitdata = {
2002 +       { PCI_VEND_DEV( INTEL, 7205_0 ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, E7205 },
2003 +       { PCI_VEND_DEV( INTEL, 7500_0 ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, E7500 },
2004 +       { PCI_VEND_DEV( INTEL, 7501_0 ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, E7501 },
2005 +       { PCI_VEND_DEV( INTEL, 7505_0 ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, E7505 },
2006 +       {0,}                                            /* 0 terminated list. */
2007 +};
2008 +
2009 +MODULE_DEVICE_TABLE(pci, e7xxx_pci_tbl);
2010 +
2011 +
2012 +static struct pci_driver e7xxx_driver = {
2013 +       .name           = BS_MOD_STR,
2014 +       .probe          = e7xxx_init_one,
2015 +       .remove         = __devexit_p(e7xxx_remove_one),
2016 +       .id_table       = e7xxx_pci_tbl,
2017 +#ifdef CONFIG_PM
2018 +       .suspend        = e7xxx_suspend,
2019 +       .resume         = e7xxx_resume,
2020 +#endif /* CONFIG_PM */
2021 +};
2022 +
2023 +
2024 +int __init e7xxx_init(void)
2025 +{
2026 +       int pci_rc;
2027 +
2028 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
2029 +       pci_rc = pci_module_init( &e7xxx_driver );
2030 +       if ( pci_rc < 0 ) return pci_rc;
2031 +
2032 +       return 0;
2033 +}
2034 +
2035 +
2036 +static void __exit e7xxx_exit(void)
2037 +{
2038 +       debugf3( "MC: "  __FILE__ ": %s()\n", __func__ );
2039 +       pci_unregister_driver( &e7xxx_driver );
2040 +}
2041 +
2042 +
2043 +module_init(e7xxx_init);
2044 +module_exit(e7xxx_exit);
2045 +
2046 +
2047 +MODULE_LICENSE("GPL");
2048 +MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n"
2049 +             "Based on.work by Dan Hollis et al");
2050 +MODULE_DESCRIPTION("MC support for Intel e7xxx memory controllers");
2051 Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_i82875p.c
2052 ===================================================================
2053 --- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/bluesmoke_i82875p.c    1969-12-31 19:00:00.000000000 -0500
2054 +++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_i82875p.c 2004-12-17 12:46:23.000000000 -0500
2055 @@ -0,0 +1,510 @@
2056 +/*
2057 + * AMD 76x Memory Controller kernel module
2058 + * (C) 2003 Linux Networx (http://lnxi.com)
2059 + * This file may be distributed under the terms of the
2060 + * GNU General Public License.
2061 + *
2062 + * Written by Thayne Harbaugh
2063 + *
2064 + * $Id: bluesmoke_i82875p.c,v 1.5 2004/11/18 22:19:46 thayne Exp $
2065 + *
2066 + */
2067 +
2068 +
2069 +#include <linux/config.h>
2070 +#include <linux/module.h>
2071 +#include <linux/init.h>
2072 +
2073 +#include <linux/pci.h>
2074 +#include <linux/pci_ids.h>
2075 +
2076 +#include <linux/slab.h>
2077 +
2078 +#include "bluesmoke_mc.h"
2079 +
2080 +
2081 +#ifndef PCI_DEVICE_ID_INTEL_82875_0
2082 +#define PCI_DEVICE_ID_INTEL_82875_0    0x2578
2083 +#endif /* PCI_DEVICE_ID_INTEL_82875_0 */
2084 +
2085 +#ifndef PCI_DEVICE_ID_INTEL_82875_6
2086 +#define PCI_DEVICE_ID_INTEL_82875_6    0x257e
2087 +#endif /* PCI_DEVICE_ID_INTEL_82875_6 */
2088 +
2089 +
2090 +/* four csrows in dual channel, eight in single channel */
2091 +#define I82875P_NR_CSROWS(nr_chans) (8/(nr_chans))
2092 +
2093 +
2094 +/* Intel 82875p register addresses - device 0 function 0 - DRAM Controller */
2095 +#define I82875P_EAP            0x58    /* Error Address Pointer (32b)
2096 +                                        *
2097 +                                        * 31:12 block address
2098 +                                        * 11:0  reserved
2099 +                                        */
2100 +
2101 +#define I82875P_DERRSYN                0x5c    /* DRAM Error Syndrome (8b)
2102 +                                        *
2103 +                                        *  7:0  DRAM ECC Syndrome
2104 +                                        */
2105 +
2106 +#define I82875P_DES            0x5d    /* DRAM Error Status (8b)
2107 +                                        *
2108 +                                        *  7:1  reserved
2109 +                                        *  0    Error channel 0/1
2110 +                                        */
2111 +
2112 +#define I82875P_ERRSTS         0xc8    /* Error Status Register (16b)
2113 +                                        *
2114 +                                        * 15:10 reserved
2115 +                                        *  9    non-DRAM lock error (ndlock)
2116 +                                        *  8    Sftwr Generated SMI
2117 +                                        *  7    ECC UE
2118 +                                        *  6    reserved
2119 +                                        *  5    MCH detects unimplemented cycle
2120 +                                        *  4    AGP access outside GA
2121 +                                        *  3    Invalid AGP access
2122 +                                        *  2    Invalid GA translation table
2123 +                                        *  1    Unsupported AGP command
2124 +                                        *  0    ECC CE
2125 +                                        */
2126 +
2127 +#define I82875P_ERRCMD         0xca    /* Error Command (16b)
2128 +                                        *
2129 +                                        * 15:10 reserved
2130 +                                        *  9    SERR on non-DRAM lock
2131 +                                        *  8    SERR on ECC UE
2132 +                                        *  7    SERR on ECC CE
2133 +                                        *  6    target abort on high exception
2134 +                                        *  5    detect unimplemented cyc
2135 +                                        *  4    AGP access outside of GA
2136 +                                        *  3    SERR on invalid AGP access
2137 +                                        *  2    invalid translation table
2138 +                                        *  1    SERR on unsupported AGP command
2139 +                                        *  0    reserved
2140 +                                        */
2141 +
2142 +
2143 +/* Intel 82875p register addresses - device 6 function 0 - DRAM Controller */
2144 +#define I82875P_PCICMD6                0x04    /* PCI Command Register (16b)
2145 +                                        *
2146 +                                        * 15:10 reserved
2147 +                                        *  9    fast back-to-back - ro 0
2148 +                                        *  8    SERR enable - ro 0
2149 +                                        *  7    addr/data stepping - ro 0
2150 +                                        *  6    parity err enable - ro 0
2151 +                                        *  5    VGA palette snoop - ro 0
2152 +                                        *  4    mem wr & invalidate - ro 0
2153 +                                        *  3    special cycle - ro 0
2154 +                                        *  2    bus master - ro 0
2155 +                                        *  1    mem access dev6 - 0(dis),1(en)
2156 +                                        *  0    IO access dev3 - 0(dis),1(en)
2157 +                                        */
2158 +
2159 +#define I82875P_BAR6           0x10    /* Mem Delays Base ADDR Reg (32b)
2160 +                                        *
2161 +                                        * 31:12 mem base addr [31:12]
2162 +                                        * 11:4  address mask - ro 0
2163 +                                        *  3    prefetchable - ro 0(non),1(pre)
2164 +                                        *  2:1  mem type - ro 0
2165 +                                        *  0    mem space - ro 0
2166 +                                        */
2167 +
2168 +/* Intel 82875p MMIO register space - device 0 function 0 - MMR space */
2169 +
2170 +#define I82875P_DRB_SHIFT 26           /* 64MiB grain */
2171 +#define I82875P_DRB            0x00    /* DRAM Row Boundary (8b x 8)
2172 +                                        *
2173 +                                        *  7    reserved
2174 +                                        *  6:0  64MiB row boundary addr
2175 +                                        */
2176 +
2177 +#define I82875P_DRA            0x10    /* DRAM Row Attribute (4b x 8)
2178 +                                        *
2179 +                                        *  7    reserved
2180 +                                        *  6:4  row attr row 1
2181 +                                        *  3    reserved
2182 +                                        *  2:0  row attr row 0
2183 +                                        *
2184 +                                        * 000 =  4KiB
2185 +                                        * 001 =  8KiB
2186 +                                        * 010 = 16KiB
2187 +                                        * 011 = 32KiB
2188 +                                        */
2189 +
2190 +#define I82875P_DRC            0x68    /* DRAM Controller Mode (32b)
2191 +                                        *
2192 +                                        * 31:30 reserved
2193 +                                        * 29    init complete
2194 +                                        * 28:23 reserved
2195 +                                        * 22:21 nr chan 00=1,01=2
2196 +                                        * 20    reserved
2197 +                                        * 19:18 Data Integ Mode 00=none,01=ecc
2198 +                                        * 17:11 reserved
2199 +                                        * 10:8  refresh mode
2200 +                                        *  7    reserved
2201 +                                        *  6:4  mode select
2202 +                                        *  3:2  reserved
2203 +                                        *  1:0  DRAM type 01=DDR
2204 +                                        */
2205 +
2206 +
2207 +enum i82875p_chips {
2208 +       I82875P = 0,
2209 +};
2210 +
2211 +
2212 +struct i82875p_pvt {
2213 +       struct pci_dev *ovrfl_pdev;
2214 +       void *ovrfl_window;
2215 +};
2216 +
2217 +
2218 +struct i82875p_dev_info {
2219 +       const char *ctl_name;
2220 +};
2221 +
2222 +
2223 +static const struct i82875p_dev_info i82875p_devs[] = {
2224 +       [I82875P] = {
2225 +               .ctl_name = "i828875p"
2226 +       },
2227 +};
2228 +
2229 +
2230 +static void i82875p_check(struct mem_ctl_info *mci)
2231 +{
2232 +       u8 des;
2233 +       u8 derrsyn;
2234 +       u16 errsts, errsts2;
2235 +       u32 eap;
2236 +       int row;
2237 +       int multi_chan = mci->csrows[0].nr_channels - 1;
2238 +
2239 +       debugf1( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
2240 +
2241 +       /*
2242 +        * This is a mess because there is no atomic way to read all
2243 +        * the registers at once and the registers can transition
2244 +        * from CE being overwritten by UE.
2245 +        */
2246 +       pci_read_config_word( mci->pdev, I82875P_ERRSTS, &errsts );
2247 +       pci_read_config_dword( mci->pdev, I82875P_EAP, &eap );
2248 +       pci_read_config_byte( mci->pdev, I82875P_DES, &des );
2249 +       pci_read_config_byte( mci->pdev, I82875P_DERRSYN, &derrsyn );
2250 +       pci_read_config_word( mci->pdev, I82875P_ERRSTS, &errsts2 );
2251 +
2252 +       pci_write_bits16( mci->pdev, I82875P_ERRSTS, 0x0081, 0x0081 );
2253 +
2254 +       /*
2255 +        * If the error is the same then we can for both reads then
2256 +        * the first set of reads is valid.  If there is a change then
2257 +        * there is a CE no info and the second set of reads is valid
2258 +        * and should be UE info.
2259 +        */
2260 +       if (! (errsts2 & 0x0081) ) return;
2261 +       if ( (errsts ^ errsts2) & 0x0081 ) {
2262 +               bluesmoke_mc_handle_ce_no_info( mci, "UE overwrote CE" );
2263 +               errsts = errsts2;
2264 +               pci_read_config_dword( mci->pdev, I82875P_EAP, &eap );
2265 +               pci_read_config_byte( mci->pdev, I82875P_DES, &des );
2266 +               pci_read_config_byte( mci->pdev, I82875P_DERRSYN, &derrsyn );
2267 +       }
2268 +
2269 +       eap >>= PAGE_SHIFT;
2270 +       row = bluesmoke_mc_find_csrow_by_page( mci, eap );
2271 +
2272 +       if ( errsts & 0x0080 ) {
2273 +               bluesmoke_mc_handle_ue( mci, eap, 0, row, "i82875p UE" );
2274 +       } else {
2275 +               bluesmoke_mc_handle_ce( mci, eap, 0, derrsyn, row,
2276 +                                       multi_chan ? (des & 0x1) : 0,
2277 +                                       "i82875p UE" );
2278 +       }
2279 +
2280 +       return;
2281 +}
2282 +
2283 +
2284 +static int i82875p_probe1( struct pci_dev *pdev, int dev_idx )
2285 +{
2286 +       int rc = -ENODEV;
2287 +       int index;
2288 +       struct mem_ctl_info *mci = NULL;
2289 +       struct i82875p_pvt *pvt = NULL;
2290 +       unsigned long last_cumul_size;
2291 +       struct pci_dev *ovrfl_pdev;
2292 +       void *ovrfl_window = NULL;
2293 +
2294 +       u32 drc;
2295 +       u32 drc_chan;           /* Number of channels 0=1chan,1=2chan */
2296 +       u32 nr_chans;
2297 +       u32 drc_ddim;           /* DRAM Data Integrity Mode 0=none,2=edac */
2298 +
2299 +       debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
2300 +
2301 +       ovrfl_pdev = pci_find_device( PCI_VEND_DEV( INTEL, 82875_6 ), NULL );
2302 +
2303 +       if ( ! ovrfl_pdev ) {
2304 +               /*
2305 +                * Intel tells BIOS developers to hide device 6 which
2306 +                * configures the overflow device access containing
2307 +                * the DRBs - this is where we expose device 6.
2308 +                * http://www.x86-secret.com/articles/tweak/pat/patsecrets-2.htm
2309 +                */
2310 +               pci_write_bits8( pdev, 0xf4, 0x2, 0x2 );
2311 +               ovrfl_pdev = pci_scan_single_device( pdev->bus, PCI_DEVFN( 6, 0 ) );
2312 +               if ( ! ovrfl_pdev ) {
2313 +                       goto FAIL_FINISHED;
2314 +               }
2315 +       }
2316 +
2317 +#ifdef CONFIG_PROC_FS
2318 +       if ( !ovrfl_pdev->procent && pci_proc_attach_device(ovrfl_pdev)) {
2319 +               printk( KERN_ERR "MC: " __FILE__
2320 +                       ": %s(): Failed to attach overflow device\n",
2321 +                       __func__ );
2322 +               goto FAIL_FINISHED;
2323 +       }
2324 +#endif /* CONFIG_PROC_FS */
2325 +       if (pci_enable_device(ovrfl_pdev)) {
2326 +               printk( KERN_ERR "MC: " __FILE__
2327 +                       ": %s(): Failed to enable overflow device\n",
2328 +                       __func__ );
2329 +               goto FAIL_FINISHED;
2330 +       }
2331 +       if (pci_request_regions(ovrfl_pdev, pci_name(ovrfl_pdev))) {
2332 +               printk( KERN_ERR "MC: " __FILE__
2333 +                       ": %s(): Failed to reserve regions - broken BIOS?\n",
2334 +                       __func__ );
2335 +#ifdef CORRECT_BIOS
2336 +               goto FAIL_FINISHED;
2337 +#endif /* CORRECT_BIOS */
2338 +       }
2339 +
2340 +       /* cache is irrelevant for PCI bus reads/writes */
2341 +       ovrfl_window = ioremap_nocache(pci_resource_start(ovrfl_pdev, 0),
2342 +                                      pci_resource_len(ovrfl_pdev, 0));
2343 +
2344 +       if (!ovrfl_window) {
2345 +               printk( KERN_ERR "MC: " __FILE__
2346 +                       ": %s(): Failed to ioremap bar6\n",
2347 +                       __func__ );
2348 +               goto FAIL_FINISHED;
2349 +       }
2350 +
2351 +       /* need to find out the number of channels */
2352 +       drc = readl(ovrfl_window + I82875P_DRC);
2353 +       drc_chan = ( ( drc >> 21 ) & 0x1 );
2354 +       nr_chans = drc_chan + 1;
2355 +       drc_ddim = ( drc >> 18 ) & 0x1;
2356 +
2357 +       mci = bluesmoke_mc_init_structs(sizeof(*pvt),
2358 +                                       I82875P_NR_CSROWS(nr_chans),
2359 +                                       nr_chans );
2360 +
2361 +       if ( ! mci ) {
2362 +               rc = -ENOMEM;
2363 +               goto FAIL_FINISHED;
2364 +       }
2365 +
2366 +       debugf3( "MC: " __FILE__ ": %s(): init mci\n", __func__ );
2367 +
2368 +       mci->pdev = pdev;
2369 +       mci->mtype_cap = MEM_FLAG_RDDR;
2370 +
2371 +       mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
2372 +       mci->edac_cap = EDAC_FLAG_UNKNOWN;
2373 +       /* adjust FLAGS */
2374 +
2375 +       mci->mod_name = BS_MOD_STR;
2376 +       mci->mod_ver = "$Revision: 1.5 $";
2377 +       mci->ctl_name = i82875p_devs[dev_idx].ctl_name;
2378 +       mci->edac_check = i82875p_check;
2379 +       mci->clear_err = NULL;
2380 +       mci->ctl_page_to_phys = NULL;
2381 +
2382 +       debugf3( "MC: " __FILE__ ": %s(): init pvt\n", __func__ );
2383 +
2384 +       pvt = (struct i82875p_pvt *)mci->pvt_info;
2385 +       pvt->ovrfl_pdev = ovrfl_pdev;
2386 +       pvt->ovrfl_window = ovrfl_window;
2387 +
2388 +       /*
2389 +        * The dram row boundary (DRB) reg values are boundary address
2390 +        * for each DRAM row with a granularity of 32 or 64MB (single/dual
2391 +        * channel operation).  DRB regs are cumulative; therefore DRB7 will
2392 +        * contain the total memory contained in all eight rows.
2393 +        */
2394 +       for( last_cumul_size = index = 0; index < mci->nr_csrows; index++ ) {
2395 +               u8 value;
2396 +               u32 cumul_size;
2397 +               struct csrow_info *csrow = &mci->csrows[ index ];
2398 +
2399 +               value = readb(ovrfl_window + I82875P_DRB + index);
2400 +               cumul_size = value << ( I82875P_DRB_SHIFT - PAGE_SHIFT );
2401 +               debugf3( "MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n",
2402 +                       __func__, index, cumul_size );
2403 +               if ( cumul_size == last_cumul_size ) {
2404 +                       continue;       /* not populated */
2405 +               }
2406 +
2407 +               csrow->first_page = last_cumul_size;
2408 +               csrow->last_page = cumul_size - 1;
2409 +               csrow->nr_pages = cumul_size - last_cumul_size;
2410 +               last_cumul_size = cumul_size;
2411 +               csrow->grain = 1 << 12; /* I82875P_EAP has 4KiB reolution */
2412 +               csrow->mtype = MEM_DDR;
2413 +               csrow->dtype = DEV_UNKNOWN;
2414 +               csrow->edac_mode = drc_ddim ? EDAC_SECDED : EDAC_NONE;
2415 +       }
2416 +
2417 +       /* clear counters */
2418 +       pci_write_bits16( mci->pdev, I82875P_ERRSTS, 0x0081, 0x0081 );
2419 +
2420 +       if ( 0 != bluesmoke_mc_add_mc( mci ) ) {
2421 +               debugf3( "MC: " __FILE__
2422 +                        ": %s(): failed bluesmoke_mc_add_mc()\n", __func__ );
2423 +               goto FAIL_FINISHED;
2424 +       }
2425 +
2426 +       /* get this far and it's successful */
2427 +       debugf3( "MC: " __FILE__ ": %s(): success\n", __func__ );
2428 +       rc = 0;
2429 +       goto FINISHED;
2430 +
2431 + FAIL_FINISHED:
2432 +       if ( mci ) {
2433 +               kfree( mci );
2434 +       }
2435 +
2436 +       if (ovrfl_window) {
2437 +               iounmap(ovrfl_window);
2438 +       }
2439 +
2440 +       if (ovrfl_pdev) {
2441 +               pci_release_regions( ovrfl_pdev );
2442 +               pci_disable_device( ovrfl_pdev );
2443 +       }
2444 +
2445 + FINISHED:
2446 +       /* NOTE: the ovrfl proc entry and pci_dev are intentionally left */
2447 +       return( rc );
2448 +}
2449 +
2450 +
2451 +#ifdef CONFIG_PM
2452 +
2453 +static int i82875p_suspend (struct pci_dev *pdev, u32 state)
2454 +{
2455 +       debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
2456 +
2457 +       return -ENOSYS;
2458 +}
2459 +
2460 +
2461 +static int i82875p_resume (struct pci_dev *pdev)
2462 +{
2463 +       debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
2464 +
2465 +       return -ENOSYS;
2466 +}
2467 +
2468 +#endif /* CONFIG_PM */
2469 +
2470 +
2471 +/* returns count (>= 0), or negative on error */
2472 +static int __devinit i82875p_init_one( struct pci_dev *pdev,
2473 +                                      const struct pci_device_id *ent )
2474 +{
2475 +       int rc;
2476 +
2477 +       debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
2478 +
2479 +       if (pci_enable_device (pdev)) {
2480 +               rc = -EIO;
2481 +       } else {
2482 +               rc = i82875p_probe1( pdev, ent->driver_data );
2483 +       }
2484 +       return rc;
2485 +}
2486 +
2487 +
2488 +static void __devexit i82875p_remove_one( struct pci_dev *pdev )
2489 +{
2490 +       struct mem_ctl_info *mci;
2491 +       struct i82875p_pvt *pvt = NULL;
2492 +
2493 +       debugf0( __FILE__ ": %s()\n", __func__);
2494 +
2495 +       if ( NULL == ( mci = bluesmoke_mc_find_mci_by_pdev( pdev ) ) ) {
2496 +               goto FINISHED;
2497 +       }
2498 +
2499 +       pvt = (struct i82875p_pvt *)mci->pvt_info;
2500 +       if (pvt->ovrfl_window) {
2501 +               iounmap(pvt->ovrfl_window);
2502 +       }
2503 +
2504 +       if (pvt->ovrfl_pdev) {
2505 +               pci_release_regions( pvt->ovrfl_pdev );
2506 +               pci_disable_device( pvt->ovrfl_pdev );
2507 +       }
2508 +
2509 +       if ( 0 != bluesmoke_mc_del_mc( mci ) ) {
2510 +               goto FINISHED;
2511 +       }
2512 +
2513 +       kfree( mci );
2514 +
2515 + FINISHED:
2516 +       return;
2517 +}
2518 +
2519 +
2520 +static const struct pci_device_id i82875p_pci_tbl[] __devinitdata = {
2521 +       { PCI_VEND_DEV( INTEL, 82875_0 ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, I82875P },
2522 +       {0,}                                            /* 0 terminated list. */
2523 +};
2524 +
2525 +MODULE_DEVICE_TABLE(pci, i82875p_pci_tbl);
2526 +
2527 +
2528 +static struct pci_driver i82875p_driver = {
2529 +       .name           = BS_MOD_STR,
2530 +       .probe          = i82875p_init_one,
2531 +       .remove         = __devexit_p(i82875p_remove_one),
2532 +       .id_table       = i82875p_pci_tbl,
2533 +#ifdef CONFIG_PM
2534 +       .suspend        = i82875p_suspend,
2535 +       .resume         = i82875p_resume,
2536 +#endif /* CONFIG_PM */
2537 +};
2538 +
2539 +
2540 +int __init i82875p_init(void)
2541 +{
2542 +       int pci_rc;
2543 +
2544 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
2545 +       pci_rc = pci_module_init( &i82875p_driver );
2546 +       if ( pci_rc < 0 ) return pci_rc;
2547 +
2548 +       return 0;
2549 +}
2550 +
2551 +
2552 +static void __exit i82875p_exit(void)
2553 +{
2554 +       debugf3( "MC: "  __FILE__ ": %s()\n", __func__ );
2555 +       pci_unregister_driver( &i82875p_driver );
2556 +}
2557 +
2558 +
2559 +module_init(i82875p_init);
2560 +module_exit(i82875p_exit);
2561 +
2562 +
2563 +MODULE_LICENSE("GPL");
2564 +MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh");
2565 +MODULE_DESCRIPTION("MC support for Intel 82875 memory hub controllers");
2566 Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_k8.c
2567 ===================================================================
2568 --- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/bluesmoke_k8.c 1969-12-31 19:00:00.000000000 -0500
2569 +++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_k8.c      2004-12-17 12:46:23.000000000 -0500
2570 @@ -0,0 +1,1252 @@
2571 +/*
2572 + * AMD K8 class Memory Controller kernel module
2573 + * (C) 2003 Linux Networx (http://lnxi.com)
2574 + * This file may be distributed under the terms of the
2575 + * GNU General Public License.
2576 + *
2577 + * Written by Thayne Harbaugh
2578 + *
2579 + * $Id: bluesmoke_k8.c,v 1.6 2004/11/23 01:34:25 thayne Exp $
2580 + *
2581 + */
2582 +
2583 +
2584 +#include <linux/config.h>
2585 +#include <linux/module.h>
2586 +#include <linux/init.h>
2587 +
2588 +#include <linux/pci.h>
2589 +#include <linux/pci_ids.h>
2590 +
2591 +#include <linux/slab.h>
2592 +
2593 +#include "bluesmoke_mc.h"
2594 +
2595 +
2596 +#ifndef PCI_DEVICE_ID_AMD_OPT_0_HT
2597 +#define PCI_DEVICE_ID_AMD_OPT_0_HT     0x1100
2598 +#endif /* PCI_DEVICE_ID_AMD_OPT_0_HT */
2599 +
2600 +#ifndef PCI_DEVICE_ID_AMD_OPT_1_ADDRMAP
2601 +#define PCI_DEVICE_ID_AMD_OPT_1_ADDRMAP        0x1101
2602 +#endif /* PCI_DEVICE_ID_AMD_OPT_1_ADDRMAP */
2603 +
2604 +#ifndef PCI_DEVICE_ID_AMD_OPT_2_MEMCTL
2605 +#define PCI_DEVICE_ID_AMD_OPT_2_MEMCTL 0x1102
2606 +#endif /* PCI_DEVICE_ID_AMD_OPT_2_MEMCTL */
2607 +
2608 +#ifndef PCI_DEVICE_ID_AMD_OPT_3_MISCCTL
2609 +#define PCI_DEVICE_ID_AMD_OPT_3_MISCCTL        0x1103
2610 +#endif /* PCI_DEVICE_ID_AMD_OPT_3_MISCCTL */
2611 +
2612 +
2613 +#define K8_NR_CSROWS 8
2614 +
2615 +
2616 +/* K8 register addresses - device 0 function 1 - Address Map */
2617 +#define K8_DBR         0x40    /* DRAM Base Register (8 x 32b
2618 +                                * interlaced with K8_DLR)
2619 +                                *
2620 +                                * 31:16 DRAM Base addr 39:24
2621 +                                * 15:11 reserved
2622 +                                * 10:8  interleave enable
2623 +                                *  7:2  reserved
2624 +                                *  1    write enable
2625 +                                *  0    read enable
2626 +                                */
2627 +#define K8_DLR         0x44    /* DRAM Limit Register (8 x 32b
2628 +                                * interlaced with K8_DBR)
2629 +                                *
2630 +                                * 31:16 DRAM Limit addr 32:24
2631 +                                * 15:11 reserved
2632 +                                * 10:8  interleave select
2633 +                                *  7:3  reserved
2634 +                                *  2:0  destination node ID
2635 +                                */
2636 +
2637 +
2638 +/* K8 register addresses - device 0 function 2 - DRAM controller */
2639 +#define K8_DCSB                0x40    /* DRAM Chip-Select Base (8 x 32b)
2640 +                                *
2641 +                                * 31:21 Base addr high 35:25
2642 +                                * 20:16 reserved
2643 +                                * 15:9  Base addr low 19:13 (interlvd)
2644 +                                *  8:1  reserved
2645 +                                *  0    chip-select bank enable
2646 +                                */
2647 +#define K8_DCSM                0x60    /* DRAM Chip-Select Mask (8 x 32b)
2648 +                                *
2649 +                                * 31:30 reserved
2650 +                                * 29:21 addr mask high 33:25
2651 +                                * 20:16 reserved
2652 +                                * 15:9  addr mask low  19:13
2653 +                                *  8:0  reserved
2654 +                                */
2655 +
2656 +#define K8_DBAM                0x80    /* DRAM Base Addr Mapping (32b) */
2657 +#define K8_DCL         0x90    /* DRAM configuration low reg (32b)
2658 +                                *
2659 +                                * 31:28 reserved
2660 +                                * 27:25 Bypass Max: 000b=respect
2661 +                                * 24    Dissable receivers - no sockets
2662 +                                * 23:20 x4 DIMMS
2663 +                                * 19    32byte chunks
2664 +                                * 18    Unbuffered
2665 +                                * 17    ECC enabled
2666 +                                * 16    128/64 bit (dual/single chan)
2667 +                                * 15:14 R/W Queue bypass count
2668 +                                * 13    Self refresh
2669 +                                * 12    exit self refresh
2670 +                                * 11    mem clear status
2671 +                                * 10    DRAM enable
2672 +                                *  9    reserved
2673 +                                *  8    DRAM init
2674 +                                *  7:4  reserved
2675 +                                *  3    dis DQS hysteresis
2676 +                                *  2    QFC enabled
2677 +                                *  1    DRAM drive strength
2678 +                                *  0    Digital Locked Loop disable
2679 +                                */
2680 +
2681 +
2682 +/* K8 register addresses - device 0 function 3 - Misc Control */
2683 +#define K8_NBCTL       0x40    /* MCA NB Control (32b)
2684 +                                *
2685 +                                *  1    MCA UE Reporting
2686 +                                *  0    MCA CE Reporting
2687 +                                */
2688 +#define K8_NBCFG       0x44    /* MCA NB Config (32b)
2689 +                                *
2690 +                                * 23    Chip-kill x4 ECC enable
2691 +                                * 22    ECC enable
2692 +                                *  1    CPU ECC enable
2693 +                                */
2694 +#define K8_NBSL                0x48    /* MCA NB Status Low (32b)
2695 +                                *
2696 +                                * 31:24 Syndrome 15:8 chip-kill x4
2697 +                                * 23:20 reserved
2698 +                                * 19:16 Extended err code
2699 +                                * 15:0  Err code
2700 +                                */
2701 +#define K8_NBSH                0x4C    /* MCA NB Status High (32b)
2702 +                                *
2703 +                                * 31    Err valid
2704 +                                * 30    Err overflow
2705 +                                * 29    Uncorrected err
2706 +                                * 28    Err enable
2707 +                                * 27    Misc err reg valid
2708 +                                * 26    Err addr valid
2709 +                                * 25    proc context corrupt
2710 +                                * 24:23 reserved
2711 +                                * 22:15 Syndrome 7:0
2712 +                                * 14    CE
2713 +                                * 13    UE
2714 +                                * 12:9  reserved
2715 +                                *  8    err found by scrubber
2716 +                                *  7    reserved
2717 +                                *  6:4  Hyper-transport link number
2718 +                                *  3:2  reserved
2719 +                                *  1    Err CPU 1
2720 +                                *  0    Err CPU 0
2721 +                                */
2722 +#define K8_NBEAL       0x50    /* MCA NB err addr low (32b)
2723 +                                *
2724 +                                * 31:3  Err addr low 31:3
2725 +                                *  2:0  reserved
2726 +                                */
2727 +#define K8_NBEAH       0x54    /* MCA NB err addr high (32b)
2728 +                                *
2729 +                                * 31:8  reserved
2730 +                                *  7:0  Err addr high 39:32
2731 +                                */
2732 +#define K8_NBCAP       0xE8    /* MCA NB capabilities (32b)
2733 +                                *
2734 +                                * 31:9  reserved
2735 +                                *  4    S4ECD4ED capable
2736 +                                *  3    SECDED capable
2737 +                                */
2738 +
2739 +
2740 +                               /* MSR's */
2741 +                               /*
2742 +                                * K8_MSR_MCxCTL (64b)
2743 +                                * (0x400,404,408,40C,410)
2744 +                                * 63    Enable reporting source 63
2745 +                                *  .
2746 +                                *  .
2747 +                                *  .
2748 +                                *  2    Enable error source 2
2749 +                                *  1    Enable error source 1
2750 +                                *  0    Enable error source 0
2751 +                                */
2752 +                               /*
2753 +                                * K8_MSR_MCxSTAT (64b)
2754 +                                * (0x401,405,409,40D,411)
2755 +                                * 63    Error valid
2756 +                                * 62    Status overflow
2757 +                                * 61    UE
2758 +                                * 60    Enabled error condition
2759 +                                * 59    Misc register valid (not used)
2760 +                                * 58    Err addr register valid
2761 +                                * 57    Processor context corrupt
2762 +                                * 56:32 Other information
2763 +                                * 31:16 Model specific error code
2764 +                                * 15:0  MCA err code
2765 +                                */
2766 +                               /*
2767 +                                * K8_MSR_MCxADDR (64b)
2768 +                                * (0x402,406,40A,40E,412)
2769 +                                * 63:48 reserved
2770 +                                * 47:0  Address
2771 +                                */
2772 +                               /*
2773 +                                * K8_MSR_MCxMISC (64b)
2774 +                                * (0x403,407,40B,40F,413)
2775 +                                * Unused on Athlon64 and K8
2776 +                                */
2777 +
2778 +#define K8_MSR_MCGCTL  0x017b  /* Machine Chk Global report ctl (64b)
2779 +                                *
2780 +                                * 31:5  reserved
2781 +                                *  4    North Bridge
2782 +                                *  3    Load/Store
2783 +                                *  2    Bus Unit
2784 +                                *  1    Instruction Cache
2785 +                                *  0    Data Cache
2786 +                                */
2787 +#define K8_MSR_MC4CTL  0x0410  /* North Bridge Check report ctl (64b) */
2788 +#define K8_MSR_MC4STAT 0x0411  /* North Bridge status (64b) */
2789 +#define K8_MSR_MC4ADDR 0x0412  /* North Bridge Address (64b) */
2790 +
2791 +
2792 +#define MCI2NID(mci)   (PCI_SLOT(mci->pdev->devfn) - 0x18)
2793 +
2794 +
2795 +enum k8_chips {
2796 +       OPTERON = 0,
2797 +};
2798 +
2799 +
2800 +struct k8_pvt {
2801 +       struct pci_dev *addr_map;
2802 +       struct pci_dev *misc_ctl;
2803 +};
2804 +
2805 +
2806 +struct k8_dev_info {
2807 +       const char *ctl_name;
2808 +       u16 addr_map;
2809 +       u16 misc_ctl;
2810 +};
2811 +
2812 +
2813 +static const struct k8_dev_info k8_devs[] = {
2814 +       [OPTERON] = {
2815 +               .ctl_name = "Athlon64/Opteron",
2816 +               .addr_map = PCI_DEVICE_ID_AMD_OPT_1_ADDRMAP,
2817 +               .misc_ctl = PCI_DEVICE_ID_AMD_OPT_3_MISCCTL
2818 +       },
2819 +};
2820 +
2821 +
2822 +static inline void pci_find_related_function( unsigned int vendor,
2823 +                                             unsigned int device,
2824 +                                             struct pci_dev **from,
2825 +                                             struct pci_dev *related )
2826 +{
2827 +       do {
2828 +               *from = pci_find_device( vendor, device, *from );
2829 +               if ( ! *from ) return;
2830 +
2831 +               if ( ((*from)->bus->number == related->bus->number)
2832 +                    && (PCI_SLOT((*from)->devfn)
2833 +                        == PCI_SLOT(related->devfn)) ) {
2834 +                       return;
2835 +               }
2836 +       } while ( 1 );
2837 +}
2838 +
2839 +
2840 +/* FIXME - stolen from msr.c - the calls in msr.c could be exported */
2841 +#ifdef CONFIG_SMP
2842 +
2843 +struct msr_command {
2844 +       int cpu;
2845 +       int err;
2846 +       u32 reg;
2847 +       u32 data[2];
2848 +};
2849 +
2850 +
2851 +static void msr_smp_wrmsr(void *cmd_block)
2852 +{
2853 +       struct msr_command *cmd = (struct msr_command *) cmd_block;
2854 +  
2855 +       debugf1( "MC: " __FILE__ ": %s(): %d ? %d\n",
2856 +                __func__, cmd->cpu, smp_processor_id() );
2857 +
2858 +       if ( cmd->cpu == smp_processor_id() ) {
2859 +               debugf1( "MC: " __FILE__ ": %s(): Matched %d\n",
2860 +                        __func__, cmd->cpu );
2861 +               wrmsr(cmd->reg, cmd->data[0], cmd->data[1]);
2862 +       }
2863 +}
2864 +
2865 +
2866 +static void msr_smp_rdmsr(void *cmd_block)
2867 +{
2868 +       struct msr_command *cmd = (struct msr_command *) cmd_block;
2869 +  
2870 +       debugf1( "MC: " __FILE__ ": %s(): %d ? %d\n",
2871 +                __func__, cmd->cpu, smp_processor_id() );
2872 +
2873 +       if ( cmd->cpu == smp_processor_id() ) {
2874 +               debugf1( "MC: " __FILE__ ": %s(): Matched %d\n",
2875 +                        __func__, cmd->cpu );
2876 +               rdmsr(cmd->reg, cmd->data[0], cmd->data[1]);
2877 +       }
2878 +}
2879 +
2880 +
2881 +static inline void do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
2882 +{
2883 +       struct msr_command cmd;
2884 +
2885 +       debugf0( "MC: " __FILE__ ": %s(): %d\n", __func__, cpu );
2886 +
2887 +       if ( cpu == smp_processor_id() ) {
2888 +               wrmsr(reg, eax, edx);
2889 +       } else {
2890 +               cmd.cpu = cpu;
2891 +               cmd.reg = reg;
2892 +               cmd.data[0] = eax;
2893 +               cmd.data[1] = edx;
2894 +    
2895 +               smp_call_function(msr_smp_wrmsr, &cmd, 1, 1);
2896 +       }
2897 +}
2898 +
2899 +
2900 +static inline void do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
2901 +{
2902 +       struct msr_command cmd;
2903 +
2904 +       debugf0( "MC: " __FILE__ ": %s(): %d\n", __func__, cpu );
2905 +
2906 +       if ( cpu == smp_processor_id() ) {
2907 +               rdmsr(reg, eax, edx);
2908 +       } else {
2909 +               cmd.cpu = cpu;
2910 +               cmd.reg = reg;
2911 +
2912 +               smp_call_function(msr_smp_rdmsr, &cmd, 1, 1);
2913 +    
2914 +               *eax = cmd.data[0];
2915 +               *edx = cmd.data[1];
2916 +       }
2917 +}
2918 +
2919 +#else /* ! CONFIG_SMP */
2920 +
2921 +static inline void do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
2922 +{
2923 +       debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
2924 +       wrmsr(reg, eax, edx);
2925 +}
2926 +
2927 +
2928 +static inline void do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
2929 +{
2930 +       debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
2931 +       rdmsr(reg, eax, edx);
2932 +}
2933 +
2934 +#endif /* ! CONFIG_SMP */
2935 +
2936 +
2937 +/*
2938 + * FIXME - This is a large chunk of memory to suck up just to decode the
2939 + * syndrome.  It would be nice to discover a patter in the syndromes that
2940 + * could be used to quickly identify the channel.  The big problems with
2941 + * this table is memory usage, lookup speed (could sort and binary search),
2942 + * correctness (there could be a transcription error).  A zero in any nibble
2943 + * for a syndrom is always channel 0, but that only decodes some of the
2944 + * syndromes.  Can anyone find any other patterns?
2945 + */
2946 +/*
2947 + * The comment in the left column is the nibble that is in error.  The least
2948 + * significant nibble of the syndrome is the mask for the bits that are
2949 + * in error (need to be toggled) for the particular nibble.
2950 + */
2951 +#define SYNDROME_TABLE_SIZE 270
2952 +static const unsigned long syndromes_chan0[SYNDROME_TABLE_SIZE] = {
2953 +       /*0*/   0xe821, 0x7c32, 0x9413, 0xbb44, 0x5365, 0xc776, 0x2f57, 0xdd88, 0x35a9, 0xa1ba, 0x499b, 0x66cc, 0x8eed, 0x1afe, 0xf2df,
2954 +       /*1*/   0x5d31, 0xa612, 0xfb23, 0x9584, 0xc8b5, 0x3396, 0x6ea7, 0xeac8, 0xb7f9, 0x4cda, 0x11eb, 0x7f4c, 0x227d, 0xd95e, 0x846f,
2955 +       /*2*/   0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
2956 +       /*3*/   0x2021, 0x3032, 0x1013, 0x4044, 0x6065, 0x7076, 0x5057, 0x8088, 0xa0a9, 0xb0ba, 0x909b, 0xc0cc, 0xe0ed, 0xf0fe, 0xd0df,
2957 +       /*4*/   0x5041, 0xa082, 0xf0c3, 0x9054, 0xc015, 0x30d6, 0x6097, 0xe0a8, 0xb0e9, 0x402a, 0x106b, 0x70fc, 0x20bd, 0xd07e, 0x803f,
2958 +       /*5*/   0xbe21, 0xd732, 0x6913, 0x2144, 0x9f65, 0xf676, 0x4857, 0x3288, 0x8ca9, 0xe5ba, 0x5b9b, 0x13cc, 0xaded, 0xc4fe, 0x7adf,
2959 +       /*6*/   0x4951, 0x8ea2, 0xc7f3, 0x5394, 0x1ac5, 0xdd36, 0x9467, 0xa1e8, 0xe8b9, 0x2f4a, 0x661b, 0xf27c, 0xbb2d, 0x7cde, 0x358f,
2960 +       /*7*/   0x74e1, 0x9872, 0xec93, 0xd6b4, 0xa255, 0x4ec6, 0x3a27, 0x6bd8, 0x1f39, 0xf3aa, 0x874b, 0xbd6c, 0xc98d, 0x251e, 0x51ff,
2961 +       /*8*/   0x15c1, 0x2a42, 0x3f83, 0xcef4, 0xdb35, 0xe4b6, 0xf177, 0x4758, 0x5299, 0x6d1a, 0x78db, 0x89ac, 0x9c6d, 0xa3ee, 0xb62f,
2962 +       /*9*/   0x3d01, 0x1602, 0x2b03, 0x8504, 0xb805, 0x9306, 0xae07, 0xca08, 0xf709, 0xdc0a, 0xe10b, 0x4f0c, 0x720d, 0x590e, 0x640f,
2963 +       /*a*/   0x9801, 0xec02, 0x7403, 0x6b04, 0xf305, 0x8706, 0x1f07, 0xbd08, 0x2509, 0x510a, 0xc90b, 0xd60c, 0x4e0d, 0x3a0e, 0xa20f,
2964 +       /*b*/   0xd131, 0x6212, 0xb323, 0x3884, 0xe9b5, 0x5a96, 0x8ba7, 0x1cc8, 0xcdf9, 0x7eda, 0xafeb, 0x244c, 0xf57d, 0x465e, 0x976f,
2965 +       /*c*/   0xe1d1, 0x7262, 0x93b3, 0xb834, 0x59e5, 0xca56, 0x2b87, 0xdc18, 0x3dc9, 0xae7a, 0x4fab, 0x542c, 0x85fd, 0x164e, 0xf79f,
2966 +       /*d*/   0x6051, 0xb0a2, 0xd0f3, 0x1094, 0x70c5, 0xa036, 0xc067, 0x20e8, 0x40b9, 0x904a, 0x601b, 0x307c, 0x502d, 0x80de, 0xe08f,
2967 +       /*e*/   0xa4c1, 0xf842, 0x5c83, 0xe6f4, 0x4235, 0x1eb6, 0xba77, 0x7b58, 0xdf99, 0x831a, 0x27db, 0x9dac, 0x396d, 0x65ee, 0xc12f,
2968 +       /*f*/   0x11c1, 0x2242, 0x3383, 0xc8f4, 0xd935, 0xeab6, 0xfb77, 0x4c58, 0x5d99, 0x6e1a, 0x7fdb, 0x84ac, 0x9562, 0xa6ee, 0xb72f,
2969 +
2970 +       /*20*/  0xbe01, 0xd702, 0x6903, 0x2104, 0x9f05, 0xf606, 0x4807, 0x3208, 0x8c09, 0xe50a, 0x5b0b, 0x130c, 0xad0d, 0xc40e, 0x7a0f,
2971 +       /*21*/  0x4101, 0x8202, 0xc303, 0x5804, 0x1905, 0xda06, 0x9b07, 0xac08, 0xed09, 0x2e0a, 0x6f0b, 0x640c, 0xb50d, 0x760e, 0x370f
2972 +};
2973 +
2974 +static const unsigned long syndromes_chan1[SYNDROME_TABLE_SIZE] = {
2975 +       /*10*/  0x45d1, 0x8a62, 0xcfb3, 0x5e34, 0x1be5, 0xd456, 0x9187, 0xa718, 0xe2c9, 0x2d7a, 0x68ab, 0xf92c, 0xbcfd, 0x734e, 0x369f,
2976 +       /*11*/  0x63e1, 0xb172, 0xd293, 0x14b4, 0x7755, 0xa5c6, 0xc627, 0x28d8, 0x4b39, 0x99aa, 0xfa4b, 0x3c6c, 0x5f8d, 0x8d1e, 0xeeff,
2977 +       /*12*/  0xb741, 0xd982, 0x6ec3, 0x2254, 0x9515, 0xfbd6, 0x4c97, 0x33a8, 0x84e9, 0xea2a, 0x5d6b, 0x11fc, 0xa6bd, 0xc87e, 0x7f3f,
2978 +       /*13*/  0xdd41, 0x6682, 0xbbc3, 0x3554, 0xe815, 0x53d6, 0xce97, 0x1aa8, 0xc7e9, 0x7c2a, 0xa1fb, 0x2ffc, 0xf2bd, 0x497e, 0x943f,
2979 +       /*14*/  0x2bd1, 0x3d62, 0x16b3, 0x4f34, 0x64e5, 0x7256, 0x5987, 0x8518, 0xaec9, 0xb87a, 0x93ab, 0xca2c, 0xe1fd, 0xf74e, 0xdc9f,
2980 +       /*15*/  0x83c1, 0xc142, 0x4283, 0xa4f4, 0x2735, 0x65b6, 0xe677, 0xf858, 0x7b99, 0x391a, 0xbadb, 0x5cac, 0xdf6d, 0x9dee, 0x1e2f,
2981 +       /*16*/  0x8fd1, 0xc562, 0x4ab3, 0xa934, 0x26e5, 0x6c56, 0xe387, 0xfe18, 0x71c9, 0x3b7a, 0xb4ab, 0x572c, 0xd8fd, 0x924e, 0x1d9f,
2982 +       /*17*/  0x4791, 0x89e2, 0xce73, 0x5264, 0x15f5, 0xdb86, 0x9c17, 0xa3b8, 0xe429, 0x2a5a, 0x6dcb, 0xf1dc, 0xb64d, 0x783e, 0x3faf,
2983 +       /*18*/  0x5781, 0xa9c2, 0xfe43, 0x92a4, 0xc525, 0x3b66, 0x6ce7, 0xe3f8, 0xb479, 0x4a3a, 0x1dbb, 0x715c, 0x26dd, 0xd89e, 0x8f1f,
2984 +       /*19*/  0xbf41, 0xd582, 0x6ac3, 0x2954, 0x9615, 0xfcd6, 0x4397, 0x3ea8, 0x81e9, 0xeb2a, 0x546b, 0x17fc, 0xa8bd, 0xc27e, 0x7d3f,
2985 +       /*1a*/  0x9891, 0xe1e2, 0x7273, 0x6464, 0xf7f5, 0x8586, 0x1617, 0xb8b8, 0x2b29, 0x595a, 0xcacb, 0xdcdc, 0x4f4d, 0x3d3e, 0xaeaf,
2986 +       /*1b*/  0xcce1, 0x4472, 0x8893, 0xfdb4, 0x3f55, 0xb9c6, 0x7527, 0x56d8, 0x9a39, 0x12aa, 0xde4b, 0xab6c, 0x678d, 0xef1e, 0x23ff,
2987 +       /*1c*/  0xa761, 0xf9b2, 0x5ed3, 0xe214, 0x4575, 0x1ba6, 0xbcc7, 0x7328, 0xd449, 0x8a9a, 0x2dfb, 0x913c, 0x365d, 0x688e, 0xcfef,
2988 +       /*1d*/  0xff61, 0x55b2, 0xaad3, 0x7914, 0x8675, 0x2ca6, 0xd3c7, 0x9e28, 0x6149, 0xcb9a, 0x34fb, 0xe73c, 0x185d, 0xb28e, 0x4def,
2989 +       /*1e*/  0x5451, 0xa8a2, 0xfcf3, 0x9694, 0xc2c5, 0x3e36, 0x6a67, 0xebe8, 0xbfb9, 0x434a, 0x171b, 0x7d7c, 0x292d, 0xd5de, 0x818f,
2990 +       /*1f*/  0x6fc1, 0xb542, 0xda83, 0x19f4, 0x7635, 0xacb6, 0xc377, 0x2e58, 0x4199, 0x9b1a, 0xf4db, 0x37ac, 0x586d, 0x82ee, 0xed2f,
2991 +                 
2992 +       /*22*/  0xc441, 0x4882, 0x8cc3, 0xf654, 0x3215, 0xbed6, 0x7a97, 0x5ba8, 0x9fe9, 0x132a, 0xd76b, 0xadfc, 0x69bd, 0xe57e, 0x213f,
2993 +       /*23*/  0x7621, 0x9b32, 0xed13, 0xda44, 0xac65, 0x4176, 0x3757, 0x6f88, 0x19a9, 0xf4ba, 0x829b, 0xb5cc, 0xc3ed, 0x2efe, 0x58df
2994 +};
2995 +
2996 +
2997 +/*
2998 + * FIXME - either the above table is borken or something is incorrect with
2999 + * the way the syndrome is read out of the NB.
3000 + */
3001 +static int chan_from_syndrome( unsigned long syndrome )
3002 +{
3003 +       int i;
3004 +
3005 +       debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
3006 +
3007 +       for ( i = 0; i < SYNDROME_TABLE_SIZE; i++ ) {
3008 +               if ( syndromes_chan0[i] == syndrome ) return 0;
3009 +               if ( syndromes_chan1[i] == syndrome ) return 1;
3010 +       }
3011 +
3012 +       debugf0( "MC: " __FILE__ ": %s(): syndrome(%lx) not found\n",
3013 +                __func__, syndrome );
3014 +       return -1;
3015 +}
3016 +
3017 +
3018 +static const char *tt_msgs[] = {       /* transaction type */
3019 +       "inst",
3020 +       "data",
3021 +       "generic",
3022 +       "reserved"
3023 +};
3024 +
3025 +
3026 +static const char *ll_msgs[] = {       /* cache level */
3027 +       "0",
3028 +       "1",
3029 +       "2",
3030 +       "generic"
3031 +};
3032 +
3033 +
3034 +static const char *memtt_msgs[] = {
3035 +       "generic",
3036 +       "generic read",
3037 +       "generic write",
3038 +       "data read",
3039 +       "data write",
3040 +       "inst fetch",
3041 +       "prefetch",
3042 +       "evict",
3043 +       "snoop",
3044 +       "unknown error 9",
3045 +       "unknown error 10",
3046 +       "unknown error 11",
3047 +       "unknown error 12",
3048 +       "unknown error 13",
3049 +       "unknown error 14",
3050 +       "unknown error 15"
3051 +};
3052 +
3053 +
3054 +static const char *pp_msgs[] = {       /* participating processor */
3055 +       "local node origin",
3056 +       "local node response",
3057 +       "local node observed",
3058 +       "generic"
3059 +};
3060 +
3061 +
3062 +static const char *to_msgs[] = {
3063 +       "no timeout",
3064 +       "timed out"
3065 +};
3066 +
3067 +
3068 +static const char *ii_msgs[] = {       /* memory or i/o */
3069 +       "mem access",
3070 +       "reserved",
3071 +       "i/o access",
3072 +       "generic"
3073 +};
3074 +
3075 +
3076 +static const char *ext_msgs[] = {      /* extended error */
3077 +       "ECC error",
3078 +       "CRC error",
3079 +       "sync error",
3080 +       "mst abort",
3081 +       "tgt abort",
3082 +       "GART error",
3083 +       "RMW error",
3084 +       "watchdog error",
3085 +       "ECC chipkill x4 error",
3086 +       "unknown error 9",
3087 +       "unknown error 10",
3088 +       "unknown error 11",
3089 +       "unknown error 12",
3090 +       "unknown error 13",
3091 +       "unknown error 14",
3092 +       "unknown error 15"
3093 +};
3094 +
3095 +
3096 +static const char *htlink_msgs[] = {
3097 +       "none",
3098 +       "1",
3099 +       "2",
3100 +       "1 2",
3101 +       "3",
3102 +       "1 3",
3103 +       "2 3",
3104 +       "1 2 3"
3105 +};
3106 +
3107 +
3108 +static inline void decode_gart_tlb_error( struct mem_ctl_info *mci,
3109 +                                         u32 nbeah, u32 nbeal,
3110 +                                         u32 nbsh, u32 nbsl,
3111 +                                         u32 nbcfg )
3112 +{
3113 +       u32 err_code;
3114 +       u32 ec_tt;      /* error code transaction type (2b) */
3115 +       u32 ec_ll;      /* error code cache level (2b) */
3116 +
3117 +       debugf0( "MC%d: " __FILE__ ": %s(): FIXME\n", mci->mc_idx, __func__ );
3118 +
3119 +       err_code = nbsl & 0xffffUL;
3120 +       ec_tt = ( err_code >> 2 ) & 0x03UL;
3121 +       ec_ll = ( err_code >> 0 ) & 0x03UL;
3122 +
3123 +       printk( "BS%d: GART TLB errorr:"
3124 +               " transaction type(%s),"
3125 +               " cache level(%s)\n",
3126 +               mci->mc_idx,
3127 +               tt_msgs[ec_tt],
3128 +               ll_msgs[ec_ll] );
3129 +}
3130 +
3131 +
3132 +static inline void decode_cache_error( struct mem_ctl_info *mci,
3133 +                                      u32 nbeah, u32 nbeal,
3134 +                                      u32 nbsh, u32 nbsl,
3135 +                                      u32 nbcfg )
3136 +{
3137 +       u32 err_code;
3138 +       u32 ec_rrrr;    /* error code memory transaction (4b) */
3139 +       u32 ec_tt;      /* error code transaction type (2b) */
3140 +       u32 ec_ll;      /* error code cache level (2b) */
3141 +
3142 +       debugf0( "MC%d: " __FILE__ ": %s(): FIXME\n", mci->mc_idx, __func__ );
3143 +
3144 +       err_code = nbsl & 0xffffUL;
3145 +       ec_rrrr = ( err_code >> 4 ) & 0x0fUL;
3146 +       ec_tt   = ( err_code >> 2 ) & 0x03UL;
3147 +       ec_ll   = ( err_code >> 0 ) & 0x03UL;
3148 +
3149 +       printk( "BS%d: cache heirarchy error:"
3150 +               " memory transaction type(%s),"
3151 +               " transaction type(%s),"
3152 +               " cache level(%s)\n",
3153 +               mci->mc_idx,
3154 +               memtt_msgs[ ec_rrrr ],
3155 +               tt_msgs[ ec_tt ],
3156 +               ll_msgs[ ec_ll ] );
3157 +}
3158 +
3159 +
3160 +static inline void decode_bus_error( struct mem_ctl_info *mci,
3161 +                                    u32 nbeah, u32 nbeal,
3162 +                                    u32 nbsh, u32 nbsl,
3163 +                                    u32 nbcfg )
3164 +{
3165 +       u32 page, offset;
3166 +       u32 err_code, ext_ec;
3167 +       int row = 0;
3168 +       u32 ec_pp;      /* error code participating processor (2p) */
3169 +       u32 ec_to;      /* error code timed out (1b) */
3170 +       u32 ec_rrrr;    /* error code memory transaction (4b) */
3171 +       u32 ec_ii;      /* error code memory or I/O (2b) */
3172 +       u32 ec_ll;      /* error code cache level (2b) */
3173 +       char msg[1024] = "";
3174 +       u32 msg_idx = 0;
3175 +
3176 +       debugf0( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
3177 +
3178 +       msg_idx = snprintf( msg, 1024, "%s", BS_MOD_STR );
3179 +
3180 +       err_code = nbsl & 0xffffUL;
3181 +       ec_pp   = ( err_code >>  9 ) & 0x03UL;
3182 +       ec_to   = ( err_code >>  8 ) & 0x01UL;
3183 +       ec_rrrr = ( err_code >>  4 ) & 0x0fUL;
3184 +       ec_ii   = ( err_code >>  2 ) & 0x03UL;
3185 +       ec_ll   = ( err_code >>  0 ) & 0x03UL;
3186 +
3187 +       ext_ec = ( nbsl >> 16 ) & 0xfUL;
3188 +
3189 +       /* FIXME - these should report through bluesmoke channels */
3190 +
3191 +       printk( "BS%d: general bus error:"
3192 +               " participating processor(%s),"
3193 +               " time-out(%s),"
3194 +               " memory transaction type(%s),"
3195 +               " mem or i/o(%s),"
3196 +               " cache level(%s)\n",
3197 +               mci->mc_idx,
3198 +               pp_msgs[ ec_pp ],
3199 +               to_msgs[ ec_to ],
3200 +               memtt_msgs[ ec_rrrr ],
3201 +               ii_msgs[ ec_ii ],
3202 +               ll_msgs[ ec_ll ] );
3203 +
3204 +       /* FIXME - other errors should have other error handling mechanisms. */
3205 +       if ( ( 0 != ext_ec ) && ( 0x8 != ext_ec ) ) {
3206 +               printk( "BS%d: no special error handling for this error\n",
3207 +                       mci->mc_idx );
3208 +               return;
3209 +       }
3210 +
3211 +       if ( ec_pp & 0x02 ) {
3212 +               /* We aren't the node involved */
3213 +               return;
3214 +       }
3215 +
3216 +       offset = nbeal & ~PAGE_MASK & ~0x7UL;
3217 +       page = ( ( nbeah & 0xff ) << ( 40 - PAGE_SHIFT ) )
3218 +               | ( ( nbeal & PAGE_MASK ) >> PAGE_SHIFT );
3219 +
3220 +       /* process any errors */
3221 +       if ( nbsh & BIT(14) ) {                 /* CE */
3222 +               unsigned long syndrome;
3223 +               int chan = 0;
3224 +
3225 +               syndrome = ( nbsh >> 15 ) & 0x00ffUL; /* bits 7:0 */
3226 +               if ( nbcfg & BIT(23) ) {
3227 +                       syndrome |= ( nbsl >> 16 ) & 0xff00UL; /* bits 15:8 */
3228 +                       chan = chan_from_syndrome( syndrome );
3229 +               }
3230 +
3231 +               if ( 0 > chan ) {
3232 +                       /*
3233 +                        * If the syndrome couldn't be found then
3234 +                        * the race condition for error reporting
3235 +                        * registers likely occurred.  There's alot
3236 +                        * more in doubt than just the channel.
3237 +                        * Might as well just log the error without
3238 +                        * any info.
3239 +                        */
3240 +                       msg_idx += snprintf( &msg[ msg_idx ], 1024 - msg_idx,
3241 +                                            " unknown syndrome 0x%lx - "
3242 +                                            " possible error reporting race",
3243 +                                            syndrome );
3244 +                       bluesmoke_mc_handle_ce_no_info( mci, msg );
3245 +               } else if ( nbsh & BIT(26) ) {          /* valid address? */
3246 +                       row = bluesmoke_mc_find_csrow_by_page( mci, page );
3247 +                       if ( -1 == row ) {
3248 +                               bluesmoke_mc_handle_ce_no_info( mci, msg );
3249 +                       } else {
3250 +                               bluesmoke_mc_handle_ce( mci, page, offset,
3251 +                                                       syndrome, row, chan,
3252 +                                                       msg );
3253 +                       }
3254 +               } else {
3255 +                       bluesmoke_mc_handle_ce_no_info( mci, msg );
3256 +               }
3257 +       } else if ( nbsh & BIT(13) ) {          /* UE */
3258 +               if ( nbsh & BIT(26) ) {         /* valid address? */
3259 +                       row = bluesmoke_mc_find_csrow_by_page( mci, page );
3260 +                       if ( -1 == row ) {
3261 +                               bluesmoke_mc_handle_ue_no_info( mci, msg );
3262 +                       } else {
3263 +                               bluesmoke_mc_handle_ue( mci, page, offset,
3264 +                                                       row, msg );
3265 +                       }
3266 +               } else {
3267 +                       bluesmoke_mc_handle_ue_no_info( mci, msg );
3268 +               }
3269 +       }
3270 +
3271 +       if ( nbsh & BIT(30) ) {
3272 +               /*
3273 +                * If main error is CE then overflow must be CE.
3274 +                * If main error is UE then overflow is unknown.
3275 +                * We'll call the overflow a CE - if panic_on_ue
3276 +                * is set then we're already panic'ed and won't
3277 +                * arrive here.  If panic_on_ue is not set then
3278 +                * apparently someone doesn't think that
3279 +                * UE's are catastrophic.
3280 +                */
3281 +               bluesmoke_mc_handle_ce_no_info( mci, BS_MOD_STR );
3282 +       }
3283 +}
3284 +
3285 +
3286 +static void k8_check(struct mem_ctl_info *mci)
3287 +{
3288 +       struct k8_pvt *pvt = (struct k8_pvt *)mci->pvt_info;
3289 +       u32 nbsl1, nbsh1, nbeal1, nbeah1, nbcfg1;
3290 +       u32 nbsl2, nbsh2, nbeal2, nbeah2, nbcfg2;
3291 +       u32 err_code;
3292 +       u32 ext_ec;
3293 +
3294 +       debugf1( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
3295 +
3296 +       /* check for an error */
3297 +       pci_read_config_dword(pvt->misc_ctl, K8_NBSH, &nbsh1);
3298 +       if ( ! (nbsh1 & BIT(31) ) ) {   /* err valid? */
3299 +               return;
3300 +       }
3301 +
3302 +       /* might as well slurp in everything at once */
3303 +       pci_read_config_dword(pvt->misc_ctl, K8_NBSL, &nbsl1);
3304 +       pci_read_config_dword(pvt->misc_ctl, K8_NBEAL, &nbeal1);
3305 +       pci_read_config_dword(pvt->misc_ctl, K8_NBEAH, &nbeah1);
3306 +       pci_read_config_dword(pvt->misc_ctl, K8_NBCFG, &nbcfg1);
3307 +       debugf1( KERN_WARNING
3308 +                "NorthBridge ERROR: mci(0x%p) node(%d) nbeah(0x%.8x)"
3309 +                " nbeal(0x%.8x) nbsh(0x%.8x) nbsl(0x%.8x): ",
3310 +                mci, MCI2NID(mci), nbeah1, nbeal1, nbsh1, nbsl1 );
3311 +
3312 +       /*
3313 +        * Here's the problem with the K8's EDAC reporting:
3314 +        * There are four registers which report pieces of error
3315 +        * information.  These four registers are shared between
3316 +        * CEs and UEs.  Furthermore, contrary to what is stated in
3317 +        * the OBKG, the overflow bit is never used!  Every error
3318 +        * always updates the reporting registers.
3319 +        *
3320 +        * Can you see the race condition?  All four error reporting
3321 +        * registers must be read before a new error updates them!
3322 +        * There is no way to read all four registers atomically.  The
3323 +        * best than can be done is to detect that a race has occured
3324 +        * and then report the error without any kind of precision.
3325 +        *
3326 +        * What is still positive is that errors are
3327 +        * still reported and thus problems can still be detected -
3328 +        * just not localized because the syndrome and address are
3329 +        * spread out across registers.
3330 +        *
3331 +        * Grrrrr!!!!!  Here's hoping that AMD fixes this in some
3332 +        * future K8 rev. UEs and CEs should have separate
3333 +        * register sets with proper overflow bits that are used!
3334 +        * At very least the problem can be fixed by honoring the
3335 +        * ErrValid bit in nbsh and not updating registers - just
3336 +        * set the overflow bit - unless the current error is CE
3337 +        * and the new error is UE which would be the only situation
3338 +        * for overwriting the current values.
3339 +        */
3340 +       pci_read_config_dword(pvt->misc_ctl, K8_NBSH, &nbsh2);
3341 +       pci_read_config_dword(pvt->misc_ctl, K8_NBSL, &nbsl2);
3342 +       pci_read_config_dword(pvt->misc_ctl, K8_NBEAL, &nbeal2);
3343 +       pci_read_config_dword(pvt->misc_ctl, K8_NBEAH, &nbeah2);
3344 +       pci_read_config_dword(pvt->misc_ctl, K8_NBCFG, &nbcfg2);
3345 +       debugf1( KERN_WARNING
3346 +                "NorthBridge ERROR2: mci(0x%p) node(%d) nbeah2(0x%.8x)"
3347 +                " nbeal2(0x%.8x) nbsh2(0x%.8x) nbsl2(0x%.8x): ",
3348 +                mci, MCI2NID(mci), nbeah2, nbeal2, nbsh2, nbsl2 );
3349 +
3350 +       /* clear the error */
3351 +       pci_write_bits32( pvt->misc_ctl, K8_NBSH, 0, BIT(31) );
3352 +
3353 +       if ( ( nbsh1 != nbsh2 )
3354 +            || ( nbsl1 != nbsl2 )
3355 +            || ( nbeah1 != nbeah2 )
3356 +            || ( nbeal1 != nbeal2 ) ) {
3357 +               printk( KERN_WARNING "MC%d: race condition detected!\n",
3358 +                       mci->mc_idx );
3359 +       }
3360 +
3361 +       err_code = nbsl2 & 0xffffUL;
3362 +       ext_ec = (nbsl2 >> 16) & 0x0fUL;
3363 +
3364 +       /* Use info from the second read - most current */
3365 +       if ( 0x0010UL == ( err_code & 0xfff0UL ) ) {
3366 +               debugf1( "GART TLB error\n" );
3367 +               decode_gart_tlb_error( mci, nbeah2, nbeal2, nbsh2, nbsl2, nbcfg2 );
3368 +       } else if ( 0x0100UL == ( err_code & 0xff00UL ) ) {
3369 +               debugf1( "Cache error\n" );
3370 +               decode_cache_error( mci, nbeah2, nbeal2, nbsh2, nbsl2, nbcfg2 );
3371 +       } else if ( 0x0800UL == ( err_code & 0xf800UL ) ) {
3372 +               debugf1( "Bus error\n" );
3373 +               decode_bus_error( mci, nbeah2, nbeal2, nbsh2, nbsl2, nbcfg2 );
3374 +       } else {
3375 +               /* shouldn't reach here! */
3376 +               printk( KERN_WARNING "MC%d: " __FILE__
3377 +                       ": %s(): unknown MCE error 0x%x\n",
3378 +                       mci->mc_idx, __func__, err_code );
3379 +       }
3380 +
3381 +       printk( "BS%d: extended error code: %s\n",
3382 +               mci->mc_idx,
3383 +               ext_msgs[ ext_ec ] );
3384 +
3385 +       if ( ((ext_ec >=1 && ext_ec <= 4) || (ext_ec == 6))
3386 +            && ((nbsh2 >> 4) & 0x03UL) ) {
3387 +               /* need to decode which hypertransport link had the error */
3388 +               u32 htln = (nbsh2 >> 4) & 0x03UL;
3389 +               printk( "BS%d: Error on hypertransport link: %s\n",
3390 +                       mci->mc_idx, htlink_msgs[ htln ] );
3391 +       }
3392 +
3393 +       /*
3394 +        * If the processor context is corrupt or the error is
3395 +        * uncorrectable then panic - why would you want to continue
3396 +        * with something seriosly broken?
3397 +        */
3398 +       if ( nbsh2 & ( BIT(29) | BIT(25) ) ) {
3399 +               if ( nbsh2 & BIT(29) )
3400 +                       printk( "BS%d: uncorrected error\n", mci->mc_idx );
3401 +
3402 +               if ( nbsh2 & BIT(25) )
3403 +                       printk( "BS%d: processor context corrupt\n",
3404 +                               mci->mc_idx );
3405 +
3406 +               panic( "BS%d: cannot recover\n", mci->mc_idx );
3407 +       };
3408 +}
3409 +
3410 +
3411 +static int k8_probe1( struct pci_dev *pdev, int dev_idx )
3412 +{
3413 +       int rc = -ENODEV;
3414 +       int index;
3415 +       struct mem_ctl_info *mci = NULL;
3416 +       struct k8_pvt *pvt = NULL;
3417 +       int nid;
3418 +       u32 dram_pg_base = 0;
3419 +       u32 dram_pg_limit = 0;
3420 +       u32 dcl;
3421 +       u32 dcl_chans;
3422 +       u32 dcl_unbuf;
3423 +       u32 dcl_x4;
3424 +       u32 dcl_eccen;
3425 +       u32 dbam;
3426 +       u32 nbcfg;
3427 +       u32 nbcfg_ckx4en;
3428 +       u32 nbcfg_eccen;
3429 +       u32 nbcap;
3430 +       u32 nbcap_ckx4;
3431 +       u32 nbcap_ecc;
3432 +       u32 csrows_loaded = 0;
3433 +       u32 mcgctl_l, mcgctl_h;
3434 +       u32 mc4ctl_l, mc4ctl_h;
3435 +       const struct k8_dev_info *k8_dev = &k8_devs[dev_idx];
3436 +
3437 +       debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
3438 +
3439 +       pci_read_config_dword(pdev, K8_DCL, &dcl);
3440 +       dcl_chans = ( dcl >> 16 ) & 0x1;
3441 +       dcl_unbuf = ( dcl >> 18 ) & 0x1;
3442 +       dcl_x4    = ( dcl >> 20 ) & 0xf;
3443 +       dcl_eccen = ( dcl >> 17 ) & 0x1;
3444 +       pci_read_config_dword(pdev, K8_DBAM, &dbam);
3445 +
3446 +       mci = bluesmoke_mc_init_structs(sizeof(*pvt),
3447 +                                       K8_NR_CSROWS,
3448 +                                       dcl_chans + 1);
3449 +
3450 +       if ( ! mci ) {
3451 +               rc = -ENOMEM;
3452 +               goto FAIL_FINISHED;
3453 +       }
3454 +
3455 +       debugf0( "MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci );
3456 +
3457 +       pvt = (struct k8_pvt *)mci->pvt_info;
3458 +
3459 +       mci->pdev = pdev;
3460 +       nid = MCI2NID(mci);
3461 +
3462 +       /* setup private structure */
3463 +       /*
3464 +        * The address mapping device provides a table that indicates
3465 +        * which physical address ranges are owned by which node.
3466 +        * Each node's memory controller  has memory controller addresses
3467 +        * that begin at 0x0.  Locally, the memory controller address
3468 +        * must be added to the mapping device address to convert to
3469 +        * physical address.
3470 +        */
3471 +       pci_find_related_function( PCI_VENDOR_ID_AMD,
3472 +                                  k8_dev->addr_map,
3473 +                                  &pvt->addr_map,
3474 +                                  mci->pdev );
3475 +
3476 +       if ( ! pvt->addr_map ) {
3477 +               printk( KERN_ERR
3478 +                       "MC: error address map device not found:"
3479 +                       "vendor %x device 0x%x (broken BIOS?)\n",
3480 +                       PCI_VENDOR_ID_AMD,
3481 +                       k8_dev->addr_map );
3482 +               goto FAIL_FINISHED;
3483 +       }
3484 +
3485 +       debugf1( "Addr Map device PCI Bus ID:\t%s\n", pvt->addr_map->name );
3486 +
3487 +       /*
3488 +        * Sift through address mapper DRAM table - the documentation isn't
3489 +        * explicit, but it is believed to be an error if there are multiple
3490 +        * entries for the same node.
3491 +        */
3492 +       for ( index = 0; index < 8; index++ ) {
3493 +               u32 dbr;
3494 +               u32 dbr_base = 0;
3495 +               u32 dbr_inten;
3496 +               u32 dbr_wen;
3497 +               u32 dbr_ren;
3498 +               u32 dlr;
3499 +               u32 dlr_limit = 0;
3500 +               u32 dlr_intsel;
3501 +               u32 dlr_nid;
3502 +
3503 +               pci_read_config_dword( pvt->addr_map,
3504 +                                      K8_DLR + (8 * index),
3505 +                                      &dlr );
3506 +
3507 +               dlr_nid = dlr & 0x7;
3508 +
3509 +               if ( dlr_nid != nid ) continue;
3510 +
3511 +               /*
3512 +                * dlr_limit has all the low-order bits 1 while dbr_base
3513 +                * has all the low-order bits 0.  Here we do some bit
3514 +                * jockeying to set all the low-order bits of dlr_limit.
3515 +                */
3516 +               dlr_limit = ((((dlr >> 16) & 0xffff) + 1)
3517 +                            << (24 - PAGE_SHIFT)) - 1;
3518 +               dlr_intsel = (dlr >> 8) & 0x1f;
3519 +
3520 +               pci_read_config_dword( pvt->addr_map,
3521 +                                      K8_DBR + (8 * index),
3522 +                                      &dbr );
3523 +
3524 +               dbr_base = ((dbr >> 16) & 0xffff) << (24 - PAGE_SHIFT);
3525 +               dbr_inten = (dbr >> 8) & 0x7;
3526 +               dbr_wen = (dbr >> 1) & 0x1;
3527 +               dbr_ren = dbr & 0x1;
3528 +
3529 +               debugf1( "\tAddr Map: %d:0x%x - 0x%x\n",
3530 +                        dlr_nid, dbr_base, dlr_limit );
3531 +
3532 +               if ( dram_pg_limit ) {
3533 +                       printk( KERN_ERR
3534 +                               "MC: multiple entries for node %d found"
3535 +                               " in Address Mapping device %s:"
3536 +                               " PROBE FAILED!\n",
3537 +                               nid, pci_name(pvt->misc_ctl) );
3538 +                       goto FAIL_FINISHED;
3539 +               }
3540 +
3541 +               dram_pg_limit = dlr_limit;
3542 +               dram_pg_base = dbr_base;
3543 +       }
3544 +
3545 +       if (! dram_pg_limit) {
3546 +               printk( KERN_ERR
3547 +                       "MC: no DRAM entry found for node %d in Address"
3548 +                       " Mapping device: %s: POBE FAILED!\n",
3549 +                       nid, pci_name(pvt->misc_ctl) );
3550 +               goto FAIL_FINISHED;
3551 +       }
3552 +
3553 +       pci_find_related_function( PCI_VENDOR_ID_AMD,
3554 +                                  k8_dev->misc_ctl,
3555 +                                  &pvt->misc_ctl,
3556 +                                  mci->pdev );
3557 +
3558 +       if ( ! pvt->misc_ctl ) {
3559 +               printk( KERN_ERR
3560 +                       "MC: error miscellaneous device not found:"
3561 +                       "vendor %x device 0x%x (broken BIOS?)\n",
3562 +                       PCI_VENDOR_ID_AMD,
3563 +                       k8_dev->misc_ctl );
3564 +               goto FAIL_FINISHED;
3565 +       }
3566 +
3567 +       debugf1( "Misc device PCI Bus ID:\t\t%.2x:%.2x.%.1x\n",
3568 +                pvt->misc_ctl->name );
3569 +
3570 +       pci_read_config_dword( pvt->misc_ctl, K8_NBCFG, &nbcfg );
3571 +       nbcfg_ckx4en = nbcfg & BIT(23);
3572 +       nbcfg_eccen  = nbcfg & BIT(22);
3573 +
3574 +       mci->mtype_cap = MEM_FLAG_DDR | MEM_FLAG_RDDR;
3575 +
3576 +       pci_read_config_dword( pvt->misc_ctl, K8_NBCAP, &nbcap );
3577 +       nbcap_ckx4 = ( nbcap >> 4 ) & 0x1;
3578 +       nbcap_ecc  = ( nbcap >> 3 ) & 0x1;
3579 +       mci->edac_ctl_cap = EDAC_FLAG_NONE;
3580 +       if ( nbcap_ecc )  mci->edac_ctl_cap |= EDAC_FLAG_SECDED;
3581 +       if ( nbcap_ckx4 ) mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED;
3582 +
3583 +       mci->edac_cap = EDAC_FLAG_NONE;
3584 +       if ( dcl_eccen ) {
3585 +               mci->edac_cap |= EDAC_FLAG_SECDED;
3586 +               if ( dcl_chans ) {
3587 +                       mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
3588 +               }
3589 +       }
3590 +
3591 +       mci->mod_name = BS_MOD_STR;
3592 +       mci->mod_ver = "$Revision: 1.6 $";
3593 +       mci->ctl_name = k8_devs[dev_idx].ctl_name;
3594 +       mci->edac_check = k8_check;
3595 +       mci->clear_err = NULL;
3596 +       mci->ctl_page_to_phys = NULL;
3597 +
3598 +       for ( index = 0; index < mci->nr_csrows; index++ ) {
3599 +               struct csrow_info *csrow = &mci->csrows[ index ];
3600 +               u32 dcsb;
3601 +               u32 dcsb_bah;
3602 +               u32 dcsb_bal;
3603 +               u32 dcsm;
3604 +               u32 dcsm_amh;
3605 +               u32 dcsm_aml;
3606 +               u32 aml;
3607 +               u32 device_shift = 0;
3608 +               u32 intlv_shift = 0;
3609 +               int i;
3610 +
3611 +               /* find the DRAM Chip Select Base address for this row */
3612 +               pci_read_config_dword(mci->pdev, K8_DCSB + (index*4), &dcsb);
3613 +               if ( ! (dcsb & 0x1) ) {
3614 +                       continue;               /* empty */
3615 +               }
3616 +               csrows_loaded++;
3617 +               dcsb_bal = ((dcsb >> 9)  & 0x7fUL)  << (13 - PAGE_SHIFT);
3618 +               dcsb_bah = ((dcsb >> 21) & 0x7ffUL) << (25 - PAGE_SHIFT);
3619 +
3620 +               pci_read_config_dword(mci->pdev, K8_DCSM + (index*4), &dcsm);
3621 +               dcsm_aml = ((~dcsm >> 9) & 0x7fUL)  << (13 - PAGE_SHIFT);
3622 +               dcsm_amh = ((dcsm >> 21) & 0x1ffUL) << (25 - PAGE_SHIFT);
3623 +
3624 +               debugf2( "\t%d: dcsb(%x) dcsm(%x)\n", index, dcsb, dcsm );
3625 +
3626 +               /* 25 is 32MiB minimum DIMM size */
3627 +               csrow->first_page = (dcsb_bah | dcsb_bal) + dram_pg_base;
3628 +               csrow->nr_pages = 1 << ((( dbam >> ((index / 2)*4) ) & 0x7)
3629 +                                       + 25 - PAGE_SHIFT + dcl_chans);
3630 +               if ( dcsm_aml ) {
3631 +                       aml = dcsm_aml;
3632 +                       i = 0;
3633 +                       while ( ! (aml & 0x1UL) ) {
3634 +                               i++;
3635 +                               aml >>= 1;
3636 +                       }
3637 +                       device_shift = i;
3638 +
3639 +                       i = 0;
3640 +                       while ( aml & 0x1UL ) {
3641 +                               i++;
3642 +                               aml >>= 1;
3643 +                       }
3644 +                       intlv_shift = i;
3645 +
3646 +                       csrow->last_page = csrow->first_page
3647 +                               + ( csrow->nr_pages << intlv_shift )
3648 +                               - ( (1 << device_shift) | 0x1UL );
3649 +               } else {
3650 +                       csrow->last_page = csrow->first_page
3651 +                               + csrow->nr_pages - 1;
3652 +               }
3653 +
3654 +               csrow->page_mask = dcsm_aml;
3655 +               csrow->grain = 8;               /* 8 bytes of resolution */
3656 +               csrow->mtype = dcl_unbuf ? MEM_DDR : MEM_RDDR;
3657 +               if ( ( dcl_x4 >> (index / 2 ) ) & 0x1 ) {
3658 +                       csrow->dtype = DEV_X4;
3659 +               } else {
3660 +                       csrow->dtype = DEV_UNKNOWN;
3661 +               }
3662 +
3663 +               if ( nbcfg_eccen ) {
3664 +                       if ( nbcfg_ckx4en ) {
3665 +                               csrow->edac_mode = EDAC_S4ECD4ED;
3666 +                       } else {
3667 +                               csrow->edac_mode = EDAC_SECDED;
3668 +                       }
3669 +               } else {
3670 +                       csrow->edac_mode = EDAC_NONE;
3671 +               }
3672 +       }
3673 +
3674 +       /* clear any pending errors, or initial state bits */
3675 +       /* FIXME - should log what is already there */
3676 +       pci_write_bits32( pvt->misc_ctl, K8_NBSH, 0, BIT(31) );
3677 +
3678 +       if ( ! csrows_loaded ) {
3679 +               mci->edac_cap = EDAC_FLAG_NONE;
3680 +       } else {
3681 +               /* turn on error reporting */
3682 +               pci_write_bits32( pvt->misc_ctl, K8_NBCTL, 0x3UL, 0x3UL );
3683 +
3684 +               pci_write_bits32( pvt->misc_ctl, K8_NBCTL, 0x3UL, 0x3UL );
3685 +
3686 +               do_rdmsr( nid, K8_MSR_MC4CTL, &mc4ctl_l, &mc4ctl_h );
3687 +               mc4ctl_l |= BIT(0) | BIT(1);
3688 +               do_wrmsr( nid, K8_MSR_MC4CTL, mc4ctl_l, mc4ctl_h );
3689 +               do_rdmsr( nid, K8_MSR_MC4CTL, &mc4ctl_l, &mc4ctl_h );
3690 +
3691 +               do_rdmsr( nid, K8_MSR_MCGCTL, &mcgctl_l, &mcgctl_h );
3692 +               mcgctl_l |= BIT(4);
3693 +               do_wrmsr( nid, K8_MSR_MCGCTL, mcgctl_l, mcgctl_h );
3694 +               do_rdmsr( nid, K8_MSR_MCGCTL, &mcgctl_l, &mcgctl_h );
3695 +       }
3696 +
3697 +       if ( 0 != bluesmoke_mc_add_mc( mci ) ) {
3698 +               debugf3( "MC: " __FILE__
3699 +                        ": %s(): failed bluesmoke_mc_add_mc()\n", __func__ );
3700 +               goto FAIL_FINISHED;
3701 +       }
3702 +
3703 +       /* get this far and it's successful */
3704 +       debugf3( "MC: " __FILE__ ": %s(): success\n", __func__ );
3705 +       rc = 0;
3706 +       goto FINISHED;
3707 +
3708 + FAIL_FINISHED:
3709 +       if ( mci ) {
3710 +               kfree( mci );
3711 +       }
3712 +
3713 + FINISHED:
3714 +       return( rc );
3715 +}
3716 +
3717 +
3718 +#ifdef CONFIG_PM
3719 +
3720 +static int k8_suspend (struct pci_dev *pdev, u32 state)
3721 +{
3722 +       debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
3723 +
3724 +       return -ENOSYS;
3725 +}
3726 +
3727 +
3728 +static int k8_resume (struct pci_dev *pdev)
3729 +{
3730 +       debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
3731 +
3732 +       return -ENOSYS;
3733 +}
3734 +
3735 +#endif /* CONFIG_PM */
3736 +
3737 +
3738 +/* returns count (>= 0), or negative on error */
3739 +static int __devinit k8_init_one( struct pci_dev *pdev,
3740 +                                 const struct pci_device_id *ent )
3741 +{
3742 +       int rc;
3743 +
3744 +       debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
3745 +
3746 +       /* wake up and enable device */         
3747 +       if (pci_enable_device (pdev)) {
3748 +               rc = -EIO;
3749 +       } else {
3750 +               rc = k8_probe1( pdev, ent->driver_data );
3751 +       }
3752 +       return rc;
3753 +}
3754 +
3755 +
3756 +static void __devexit k8_remove_one( struct pci_dev *pdev )
3757 +{
3758 +       struct mem_ctl_info *mci;
3759 +
3760 +       debugf0( __FILE__ ": %s()\n", __func__);
3761 +
3762 +       if ( NULL == ( mci = bluesmoke_mc_find_mci_by_pdev( pdev ) ) ) {
3763 +               goto FINISHED;
3764 +       }
3765 +
3766 +       if ( 0 != bluesmoke_mc_del_mc( mci ) ) {
3767 +               goto FINISHED;
3768 +       }
3769 +
3770 +       kfree( mci );
3771 +
3772 + FINISHED:
3773 +       return;
3774 +}
3775 +
3776 +
3777 +static const struct pci_device_id k8_pci_tbl[] __devinitdata = {
3778 +       { PCI_VEND_DEV( AMD, OPT_2_MEMCTL ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, OPTERON },
3779 +       {0,}                                            /* 0 terminated list. */
3780 +};
3781 +
3782 +MODULE_DEVICE_TABLE(pci, k8_pci_tbl);
3783 +
3784 +
3785 +static struct pci_driver k8_driver = {
3786 +       .name           = BS_MOD_STR,
3787 +       .probe          = k8_init_one,
3788 +       .remove         = __devexit_p(k8_remove_one),
3789 +       .id_table       = k8_pci_tbl,
3790 +#ifdef CONFIG_PM
3791 +       .suspend        = k8_suspend,
3792 +       .resume         = k8_resume,
3793 +#endif /* CONFIG_PM */
3794 +};
3795 +
3796 +
3797 +int __init k8_init(void)
3798 +{
3799 +       int pci_rc;
3800 +
3801 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
3802 +       pci_rc = pci_module_init( &k8_driver );
3803 +       if ( pci_rc < 0 ) return pci_rc;
3804 +
3805 +       return 0;
3806 +}
3807 +
3808 +
3809 +static void __exit k8_exit(void)
3810 +{
3811 +       debugf3( "MC: "  __FILE__ ": %s()\n", __func__ );
3812 +       pci_unregister_driver( &k8_driver );
3813 +}
3814 +
3815 +
3816 +module_init(k8_init);
3817 +module_exit(k8_exit);
3818 +
3819 +
3820 +MODULE_LICENSE("GPL");
3821 +MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh");
3822 +MODULE_DESCRIPTION("MC support for AMD K8 memory controllers");
3823 Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_mc.c
3824 ===================================================================
3825 --- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/bluesmoke_mc.c 1969-12-31 19:00:00.000000000 -0500
3826 +++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_mc.c      2004-12-17 12:46:23.000000000 -0500
3827 @@ -0,0 +1,1112 @@
3828 +/*
3829 + * bluesmoke_mc kernel module
3830 + * (C) 2003 Linux Networx (http://lnxi.com)
3831 + * This file may be distributed under the terms of the
3832 + * GNU General Public License.
3833 + *
3834 + * Written by Thayne Harbaugh
3835 + * Based on work by Dan Hollis <goemon at anime dot net> and others.
3836 + *     http://www.anime.net/~goemon/linux-ecc/
3837 + *
3838 + * $Id: bluesmoke_mc.c,v 1.9 2004/12/13 22:19:40 thayne Exp $
3839 + *
3840 + */
3841 +
3842 +
3843 +#include <linux/config.h>
3844 +#include <linux/version.h>
3845 +#include <linux/module.h>
3846 +#include <linux/proc_fs.h>
3847 +#include <linux/kernel.h>
3848 +#include <linux/init.h>
3849 +#include <linux/sysctl.h>
3850 +#include <linux/highmem.h>
3851 +#include <linux/timer.h>
3852 +#include <linux/slab.h>
3853 +
3854 +#include <asm/uaccess.h>
3855 +#include <asm/page.h>
3856 +
3857 +#include "bluesmoke_mc.h"
3858 +
3859 +
3860 +#ifndef pfn_to_page
3861 +#define pfn_to_page(pfn)       (mem_map + (pfn)) 
3862 +#endif /* pfn_to_page */
3863 +
3864 +#define MC_PROC_DIR "mc"
3865 +
3866 +/* /proc/mc dir */
3867 +static struct proc_dir_entry *proc_mc;
3868 +
3869 +/* Setable by module parameter and sysctl */
3870 +#if SCRUB
3871 +/* FIXME - do something with scrubbing */
3872 +static int mc_scrub            = -1;
3873 +#endif /* SCRUB */
3874 +static int panic_on_ue         = 1;
3875 +static int log_ue              = 1;
3876 +static int log_ce              = 1;
3877 +static int poll_msec           = 1000;
3878 +static struct timer_list timer;
3879 +
3880 +static DECLARE_MUTEX(mem_ctls_mutex);
3881 +
3882 +/* FIXME - use list.h */
3883 +/* FIXME - should be dynamic */
3884 +static struct mem_ctl_info *mcis[MAX_MC_DEVICES];
3885 +
3886 +
3887 +#ifdef CONFIG_SYSCTL
3888 +static void dimm_labels( char *buf, void *data )
3889 +{
3890 +       int mcidx, ridx, chidx;
3891 +       char *mcstr, *rstr, *chstr, *lstr, *p;
3892 +
3893 +       lstr = buf;
3894 +
3895 +       mcstr = strsep( &lstr, "." );
3896 +       if (! lstr)
3897 +               return;
3898 +       mcidx = simple_strtol( mcstr, &p, 0 );
3899 +       if ( *p )
3900 +               return;
3901 +       if ( mcidx >= MAX_MC_DEVICES || ! mcis[mcidx] )
3902 +               return;
3903 +
3904 +       rstr = strsep( &lstr, "." );
3905 +       if (! lstr)
3906 +               return;
3907 +       ridx = simple_strtol( rstr, &p, 0 );
3908 +       if ( *p )
3909 +               return;
3910 +       if ( ridx >= mcis[mcidx]->nr_csrows
3911 +            || ! mcis[mcidx]->csrows )
3912 +               return;
3913 +
3914 +       chstr = strsep( &lstr, ":" );
3915 +       if (! lstr)
3916 +               return;
3917 +       chidx = simple_strtol( chstr, &p, 0 );
3918 +       if ( *p )
3919 +               return;
3920 +       if ( chidx >= mcis[mcidx]->csrows[ridx].nr_channels
3921 +            || ! mcis[mcidx]->csrows[ridx].channels )
3922 +               return;
3923 +
3924 +       debugf1( "%d:%d.%d:%s\n",
3925 +                mcidx, ridx, chidx, lstr );
3926 +
3927 +       strncpy(mcis[mcidx]->csrows[ridx].channels[chidx].label,
3928 +               lstr, BLUESMOKE_MC_LABEL_LEN + 1);
3929 +       /*
3930 +        * no need to NUL terminate label since
3931 +        * get_user_tok() NUL terminates.
3932 +        */
3933 +}
3934 +
3935 +
3936 +static void counter_reset( char *buf, void *data )
3937 +{
3938 +       char *p = buf;
3939 +       int mcidx, row, chan;
3940 +       struct mem_ctl_info *mci;
3941 +
3942 +       mcidx = simple_strtol( buf, &p, 0 );
3943 +       if ( *p )
3944 +               return;
3945 +       if ( mcidx >= MAX_MC_DEVICES || ! mcis[mcidx] )
3946 +               return;
3947 +
3948 +       mci = mcis[mcidx];
3949 +       mci->ue_noinfo_count = 0;
3950 +       mci->ce_noinfo_count = 0;
3951 +       mci->ue_count = 0;
3952 +       mci->ce_count = 0;
3953 +       for ( row = 0; row < mci->nr_csrows; row++ ) {
3954 +               struct csrow_info *ri = &mci->csrows[row];
3955 +
3956 +               ri->ue_count = 0;
3957 +               ri->ce_count = 0;
3958 +               for ( chan = 0; chan < ri->nr_channels; chan++ ) {
3959 +                       ri->channels[chan].ce_count = 0;
3960 +               }
3961 +       }
3962 +       do_gettimeofday( &mci->tv );
3963 +}
3964 +
3965 +
3966 +struct actionvec_info {
3967 +       void (*action)(char *str, void *data);
3968 +       char separator;
3969 +       char *usage;
3970 +       void *data;
3971 +};
3972 +
3973 +
3974 +static struct actionvec_info dimm_labels_avi = {
3975 +       .action    = dimm_labels,
3976 +       .separator = ',',
3977 +       .usage     = "<mc>.<row>.<chan>:<label>"
3978 +       "[,<mc>.<row>.<chan>:<label>[,...]]\n",
3979 +       .data      = NULL
3980 +};
3981 +
3982 +
3983 +static struct actionvec_info counter_reset_avi = {
3984 +       .action    = counter_reset,
3985 +       .separator = ',',
3986 +       .usage     = "<mc>[,<mc>[,...]]\n",
3987 +       .data      = NULL
3988 +};
3989 +
3990 +
3991 +static int proc_actionvec( ctl_table *table, int write, struct file *filp,
3992 +                          void *buffer, size_t *lenp )
3993 +{
3994 +       size_t len;
3995 +       char *p, c, *buf, *tok, sep[] = " ";
3996 +       struct actionvec_info *avi;
3997 +       
3998 +       debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
3999 +
4000 +       if ( !table->data || !*lenp || (filp->f_pos && !write)) {
4001 +               *lenp = 0;
4002 +               return 0;
4003 +       }
4004 +
4005 +       avi = (struct actionvec_info *)table->data;
4006 +       
4007 +       if (write) {
4008 +               /* dup the string from user space */
4009 +               len = 0;
4010 +               p = buffer;
4011 +               while (len < *lenp) {
4012 +                       if (get_user(c, p++))
4013 +                               return -EFAULT;
4014 +                       if (c == 0 || c == '\n')
4015 +                               break;
4016 +                       len++;
4017 +               }
4018 +               if (! (buf = kmalloc(len + 1, GFP_KERNEL)))
4019 +                       return -EFAULT;
4020 +               if (copy_from_user(buf, buffer, len)) {
4021 +                       kfree(buf);
4022 +                       return -EFAULT;
4023 +               }
4024 +               buf[len] = '\0';
4025 +               filp->f_pos += *lenp;
4026 +               /* working copy can now be segmented for processing */
4027 +               p = buf;
4028 +               sep[0] = avi->separator;
4029 +               while ((tok = strsep(&p, sep)))
4030 +                       avi->action(tok, avi->data);
4031 +               kfree(buf);
4032 +       } else {
4033 +               len = strlen(avi->usage);
4034 +               if (len > *lenp)
4035 +                       len = *lenp;
4036 +               if (len)
4037 +                       if(copy_to_user(buffer, avi->usage, len))
4038 +                               return -EFAULT;
4039 +               *lenp = len;
4040 +               filp->f_pos += len;
4041 +       }
4042 +       return 0;
4043 +}
4044 +
4045 +
4046 +static ctl_table mc_table[] = {
4047 +        {-1, "panic_on_ue", &panic_on_ue,
4048 +        sizeof(int), 0644, NULL, proc_dointvec},
4049 +        {-2, "log_ue", &log_ue,
4050 +        sizeof(int), 0644, NULL, proc_dointvec},
4051 +        {-3, "log_ce", &log_ce,
4052 +        sizeof(int), 0644, NULL, proc_dointvec},
4053 +        {-4, "poll_msec", &poll_msec,
4054 +        sizeof(int), 0644, NULL, proc_dointvec},
4055 +        {-5, "dimm_labels", &dimm_labels_avi,
4056 +        0, 0644, NULL, proc_actionvec},
4057 +        {-6, "counter_reset", &counter_reset_avi,
4058 +        0, 0644, NULL, proc_actionvec},
4059 +        {0}
4060 +};
4061 +
4062 +
4063 +static ctl_table mc_root_table[] = {
4064 +        {CTL_DEBUG, MC_PROC_DIR, NULL, 0, 0555, mc_table},
4065 +        {0}
4066 +};
4067 +
4068 +
4069 +static struct ctl_table_header *mc_sysctl_header = NULL;
4070 +#endif /* CONFIG_SYSCTL */
4071 +
4072 +
4073 +#ifdef CONFIG_PROC_FS
4074 +static const char *mem_types[] = {
4075 +       [MEM_EMPTY]             = "Empty",
4076 +       [MEM_RESERVED]          = "Reserved",
4077 +       [MEM_UNKNOWN]           = "Unknown",
4078 +       [MEM_FPM]               = "FPM",
4079 +       [MEM_EDO]               = "EDO",
4080 +       [MEM_BEDO]              = "BEDO",
4081 +       [MEM_SDR]               = "Unbuffered-SDR",
4082 +       [MEM_RDR]               = "Registered-SDR",
4083 +       [MEM_DDR]               = "Unbuffered-DDR",
4084 +       [MEM_RDDR]              = "Registered-DDR",
4085 +       [MEM_RMBS]              = "RMBS"
4086 +};
4087 +
4088 +static const char *dev_types[] = {
4089 +       [DEV_UNKNOWN]           = "Unknown",
4090 +       [DEV_X1]                = "x1",
4091 +       [DEV_X2]                = "x2",
4092 +       [DEV_X4]                = "x4",
4093 +       [DEV_X8]                = "x8",
4094 +       [DEV_X16]               = "x16",
4095 +       [DEV_X32]               = "x32",
4096 +       [DEV_X64]               = "x64"
4097 +};
4098 +
4099 +static const char *edac_caps[] = {
4100 +       [EDAC_UNKNOWN]          = "Unknown",
4101 +       [EDAC_NONE]             = "None",
4102 +       [EDAC_RESERVED]         = "Reserved",
4103 +       [EDAC_PARITY]           = "PARITY",
4104 +       [EDAC_EC]               = "EC",
4105 +       [EDAC_SECDED]           = "SECDED",
4106 +       [EDAC_S2ECD2ED]         = "S2ECD2ED",
4107 +       [EDAC_S4ECD4ED]         = "S4ECD4ED",
4108 +       [EDAC_S8ECD8ED]         = "S8ECD8ED",
4109 +       [EDAC_S16ECD16ED]       = "S16ECD16ED"
4110 +};
4111 +
4112 +
4113 +#if UNUSED
4114 +static const char *scrub_caps[] = {
4115 +       [SCRUB_UNKNOWN]         = "Unknown",
4116 +       [SCRUB_NONE]            = "None",
4117 +       [SCRUB_SW_PROG]         = "SProg",
4118 +       [SCRUB_SW_SRC]          = "SSrc",
4119 +       [SCRUB_SW_PROG_SRC]     = "SProg+Src",
4120 +       [SCRUB_SW_TUNABLE]      = "STun",
4121 +       [SCRUB_HW_PROG]         = "HProg",
4122 +       [SCRUB_HW_SRC]          = "HSrc",
4123 +       [SCRUB_HW_PROG_SRC]     = "HProg+Src",
4124 +       [SCRUB_HW_TUNABLE]      = "HTun"
4125 +};
4126 +#endif /* UNUSED */
4127 +
4128 +
4129 +/* FIXME - CHANNEL_PREFIX is pretty bad */
4130 +#define CHANNEL_PREFIX(...) \
4131 +       do { \
4132 +               p += sprintf( p, "%d.%d:%s", \
4133 +                       chan->csrow->csrow_idx, \
4134 +                       chan->chan_idx, \
4135 +                       chan->label ); \
4136 +               p += sprintf( p, ":" __VA_ARGS__ ); \
4137 +       } while ( 0 )
4138 +
4139 +
4140 +static inline int mc_proc_output_channel(char *buf, struct channel_info *chan)
4141 +{
4142 +       char *p = buf;
4143 +
4144 +       CHANNEL_PREFIX( "CE:\t\t%d\n", chan->ce_count );
4145 +
4146 +       return p - buf;
4147 +}
4148 +
4149 +#undef CHANNEL_PREFIX
4150 +
4151 +
4152 +#define CSROW_PREFIX(...) \
4153 +       do { \
4154 +               int i; \
4155 +               p += sprintf( p, "%d:", csrow->csrow_idx ); \
4156 +               p += sprintf( p, "%s", csrow->channels[0].label ); \
4157 +               for ( i = 1; i < csrow->nr_channels; i++ ) { \
4158 +                       p += sprintf( p, "|%s", csrow->channels[i].label ); \
4159 +               } \
4160 +               p += sprintf( p, ":" __VA_ARGS__ ); \
4161 +       } while ( 0 )
4162 +
4163 +
4164 +static inline int mc_proc_output_csrow(char *buf, struct csrow_info *csrow)
4165 +{
4166 +       char *p = buf;
4167 +       int chan_idx;
4168 +
4169 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
4170 +
4171 +       CSROW_PREFIX( "Memory Size:\t%d MiB\n",
4172 +                    (u32)PAGES_TO_MiB(csrow->nr_pages) );
4173 +       CSROW_PREFIX( "Mem Type:\t\t%s\n", mem_types[csrow->mtype] );
4174 +       CSROW_PREFIX( "Dev Type:\t\t%s\n", dev_types[csrow->dtype] );
4175 +       CSROW_PREFIX( "EDAC Mode:\t\t%s\n", edac_caps[csrow->edac_mode] );
4176 +       CSROW_PREFIX( "UE:\t\t\t%d\n", csrow->ue_count );
4177 +       CSROW_PREFIX( "CE:\t\t\t%d\n", csrow->ce_count );
4178 +
4179 +       for ( chan_idx = 0; chan_idx < csrow->nr_channels; chan_idx++ ) {
4180 +               p += mc_proc_output_channel( p, &csrow->channels[chan_idx] );
4181 +       }
4182 +       p += sprintf( p, "\n" );
4183 +       return p - buf;
4184 +}
4185 +
4186 +#undef CSROW_PREFIX
4187 +
4188 +
4189 +static inline int mc_proc_output_edac_cap(char *buf, unsigned long edac_cap)
4190 +{
4191 +       char *p = buf;
4192 +       int bit_idx;
4193 +
4194 +       for ( bit_idx = 0; bit_idx < 8 * sizeof(edac_cap); bit_idx++ ) {
4195 +               if ( ( edac_cap >> bit_idx ) & 0x1 ) {
4196 +                       p += sprintf( p, "%s ", edac_caps[ bit_idx ] );
4197 +               }
4198 +       }
4199 +
4200 +       return p - buf;
4201 +}
4202 +
4203 +
4204 +static inline int mc_proc_output_mtype_cap(char *buf, unsigned long mtype_cap)
4205 +{
4206 +       char *p = buf;
4207 +       int bit_idx;
4208 +
4209 +       for ( bit_idx = 0; bit_idx < 8 * sizeof(mtype_cap); bit_idx++ ) {
4210 +               if ( ( mtype_cap >> bit_idx ) & 0x1 ) {
4211 +                       p += sprintf( p, "%s ", mem_types[ bit_idx ] );
4212 +               }
4213 +       }
4214 +
4215 +       return p - buf;
4216 +}
4217 +
4218 +
4219 +static int mc_proc_output(struct mem_ctl_info *mci, char *buf)
4220 +{      
4221 +       int csrow_idx;
4222 +       u32 total_pages;
4223 +       char *p = buf;
4224 +       struct timeval tv;
4225 +
4226 +       debugf3( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
4227 +
4228 +       do_gettimeofday( &tv );
4229 +
4230 +       p += sprintf( p, "Panic UE:\t\t%d\n",    panic_on_ue );
4231 +       p += sprintf( p, "Log UE:\t\t\t%d\n",    log_ue );
4232 +       p += sprintf( p, "Log CE:\t\t\t%d\n",    log_ce );
4233 +       p += sprintf( p, "Poll msec:\t\t%d\n",   poll_msec );
4234 +
4235 +       p += sprintf( p, "\n" );
4236 +
4237 +       p += sprintf( p, "MC Module:\t\t%s %s\n", mci->mod_name, mci->mod_ver );
4238 +       p += sprintf( p, "Memory Controller:\t%s\n", mci->ctl_name );
4239 +       p += sprintf( p, "PCI Bus ID:\t\t%s (%s)\n",
4240 +                     mci->pdev->slot_name, pci_name(mci->pdev) );
4241 +
4242 +       p += sprintf( p, "EDAC capability:\t" );
4243 +       p += mc_proc_output_edac_cap( p, mci->edac_ctl_cap );
4244 +       p += sprintf( p, "\n" );
4245 +
4246 +       p += sprintf( p, "Current EDAC capability:\t" );
4247 +       p += mc_proc_output_edac_cap( p, mci->edac_cap );
4248 +       p += sprintf( p, "\n" );
4249 +
4250 +       p += sprintf( p, "Supported Mem Types:\t" );
4251 +       p += mc_proc_output_mtype_cap( p, mci->mtype_cap );
4252 +       p += sprintf( p, "\n" );
4253 +
4254 +       p += sprintf( p, "\n" );
4255 +
4256 +       for ( total_pages = csrow_idx = 0;
4257 +             csrow_idx < mci->nr_csrows;
4258 +             csrow_idx++ ) {
4259 +               struct csrow_info *csrow = &mci->csrows[csrow_idx];
4260 +
4261 +               if ( ! csrow->nr_pages ) continue;
4262 +               total_pages += csrow->nr_pages;
4263 +               p += mc_proc_output_csrow( p, csrow );
4264 +       }
4265 +
4266 +       p += sprintf( p, "Total Memory Size:\t%d MiB\n",
4267 +                     (u32)PAGES_TO_MiB(total_pages) );
4268 +       p += sprintf( p, "Seconds since reset:\t%ld\n",
4269 +                     tv.tv_sec - mci->tv.tv_sec );
4270 +       p += sprintf( p, "UE No Info:\t\t%d\n", mci->ue_noinfo_count );
4271 +       p += sprintf( p, "CE No Info:\t\t%d\n", mci->ce_noinfo_count );
4272 +       p += sprintf( p, "Total UE:\t\t%d\n", mci->ue_count );
4273 +       p += sprintf( p, "Total CE:\t\t%d\n", mci->ce_count );
4274 +       return p - buf;
4275 +}
4276 +
4277 +
4278 +static int mc_read_proc(char *page, char **start, off_t off,
4279 +                            int count, int *eof, void *data)
4280 +{
4281 +       int len;
4282 +       struct mem_ctl_info *mci = (struct mem_ctl_info *)data;
4283 +
4284 +       debugf3( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
4285 +
4286 +       down(&mem_ctls_mutex);
4287 +        len = mc_proc_output(mci, page);
4288 +       up(&mem_ctls_mutex);
4289 +        if (len <= off+count) *eof = 1;
4290 +        *start = page + off;
4291 +        len -= off;
4292 +        if (len>count) len = count;
4293 +        if (len<0) len = 0;
4294 +
4295 +
4296 +        return len;
4297 +}
4298 +#endif /* CONFIG_PROC_FS */
4299 +
4300 +
4301 +#if CONFIG_BLUESMOKE_DEBUG
4302 +
4303 +
4304 +EXPORT_SYMBOL(bluesmoke_mc_dump_channel);
4305 +
4306 +void bluesmoke_mc_dump_channel( struct channel_info *chan )
4307 +{
4308 +       printk( KERN_INFO "\tchannel = %p\n", chan );
4309 +       printk( KERN_INFO "\tchannel->chan_idx = %d\n", chan->chan_idx );
4310 +       printk( KERN_INFO "\tchannel->ce_count = %d\n", chan->ce_count );
4311 +       printk( KERN_INFO "\tchannel->label = '%s'\n", chan->label );
4312 +       printk( KERN_INFO "\tchannel->csrow = %p\n\n", chan->csrow );
4313 +}
4314 +
4315 +
4316 +EXPORT_SYMBOL(bluesmoke_mc_dump_csrow);
4317 +
4318 +void bluesmoke_mc_dump_csrow( struct csrow_info *csrow )
4319 +{
4320 +       printk( KERN_INFO "\tcsrow = %p\n", csrow );
4321 +       printk( KERN_INFO "\tcsrow->csrow_idx = %d\n", csrow->csrow_idx );
4322 +       printk( KERN_INFO "\tcsrow->first_page = 0x%lx\n", csrow->first_page );
4323 +       printk( KERN_INFO "\tcsrow->last_page = 0x%lx\n", csrow->last_page );
4324 +       printk( KERN_INFO "\tcsrow->page_mask = 0x%lx\n", csrow->page_mask );
4325 +       printk( KERN_INFO "\tcsrow->nr_pages = 0x%x\n", csrow->nr_pages );
4326 +       printk( KERN_INFO "\tcsrow->nr_channels = %d\n", csrow->nr_channels );
4327 +       printk( KERN_INFO "\tcsrow->channels = %p\n", csrow->channels );
4328 +       printk( KERN_INFO "\tcsrow->mci = %p\n\n", csrow->mci );
4329 +}
4330 +
4331 +
4332 +EXPORT_SYMBOL(bluesmoke_mc_dump_mci);
4333 +
4334 +void bluesmoke_mc_dump_mci( struct mem_ctl_info *mci )
4335 +{
4336 +       printk( KERN_INFO "\tmci = %p\n", mci );
4337 +       printk( KERN_INFO "\tmci->mtype_cap = %lx\n", mci->mtype_cap );
4338 +       printk( KERN_INFO "\tmci->edac_ctl_cap = %lx\n", mci->edac_ctl_cap );
4339 +       printk( KERN_INFO "\tmci->edac_cap = %lx\n", mci->edac_cap );
4340 +       printk( KERN_INFO "\tmci->edac_check = %p\n", mci->edac_check );
4341 +       printk( KERN_INFO "\tmci->clear_err = %p\n", mci->clear_err );
4342 +       printk( KERN_INFO "\tmci->nr_csrows = %d, csrows = %p\n",
4343 +               mci->nr_csrows, mci->csrows );
4344 +       printk( KERN_INFO "\tpdev = %p\n", mci->pdev );
4345 +       printk( KERN_INFO "\tmod_name:ctl_name = %s:%s\n",
4346 +               mci->mod_name, mci->ctl_name );
4347 +       printk( KERN_INFO "\tproc_name = %s, proc_ent = %p\n",
4348 +               mci->proc_name, mci->proc_ent );
4349 +       printk( KERN_INFO "\tpvt_info = %p\n\n", mci->pvt_info );
4350 +}
4351 +
4352 +
4353 +#endif /* CONFIG_BLUESMOKE_DEBUG */
4354 +
4355 +
4356 +EXPORT_SYMBOL(bluesmoke_mc_init_structs);
4357 +
4358 +/*
4359 + * Everything is kmalloc'ed as one big chunk - more efficient.
4360 + * Only can be used if all structures have the same lifetime - otherwise
4361 + * you have to allocate and initialize your own structures.
4362 + *
4363 + * kmalloc'ed memory must be free'ed by caller.
4364 + */
4365 +struct mem_ctl_info *bluesmoke_mc_init_structs(u32 sz_pvt,
4366 +                                              u32 nr_csrows,
4367 +                                              u32 nr_chans)
4368 +{
4369 +       struct mem_ctl_info *mci;
4370 +       struct channel_info *chi;
4371 +       u32 malloc_size;
4372 +       int row, chn;
4373 +
4374 +       malloc_size =
4375 +               sizeof(struct mem_ctl_info)
4376 +               + sz_pvt
4377 +               + nr_csrows * sizeof(struct csrow_info)
4378 +               + nr_chans * nr_csrows * sizeof(struct channel_info);
4379 +
4380 +       if (! (mci = kmalloc(malloc_size, GFP_KERNEL)))
4381 +               goto done;
4382 +
4383 +       memset( mci, 0, malloc_size);
4384 +
4385 +       /* set all the pointers to the correct offset in the malloc'ed block */
4386 +       if (sz_pvt)
4387 +               mci->pvt_info = (pvt_info_t)((char *)mci + sizeof(*mci));
4388 +
4389 +       mci->csrows = (struct csrow_info *)((char *)mci + sizeof(*mci) + sz_pvt);
4390 +       mci->nr_csrows = nr_csrows;
4391 +
4392 +       chi = (struct channel_info *)((char *)mci->csrows
4393 +                                     + sizeof(*mci->csrows) * nr_csrows);
4394 +
4395 +       for (row = 0; row < nr_csrows; row++) {
4396 +               struct csrow_info *csrow = &mci->csrows[row];
4397 +
4398 +               csrow->csrow_idx = row;
4399 +               csrow->mci = mci;
4400 +               csrow->nr_channels = nr_chans;
4401 +               csrow->channels = &chi[ row * nr_chans ];
4402 +
4403 +               for (chn = 0; chn < nr_chans; chn++) {
4404 +                       struct channel_info *chan = &csrow->channels[ chn ];
4405 +
4406 +                       chan->chan_idx = chn;
4407 +                       chan->csrow = csrow;
4408 +               }
4409 +       }
4410 +
4411 + done:
4412 +       return mci;
4413 +}
4414 +
4415 +
4416 +EXPORT_SYMBOL(bluesmoke_mc_find_mci_by_pdev);
4417 +
4418 +struct mem_ctl_info *bluesmoke_mc_find_mci_by_pdev(struct pci_dev *pdev )
4419 +{
4420 +       int i;
4421 +       struct mem_ctl_info *mci = NULL;
4422 +
4423 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
4424 +
4425 +       for (i=0; i < MAX_MC_DEVICES; i++) {
4426 +               if ( ! mcis[ i ] ) continue;
4427 +               if ( pdev == mcis[ i ]->pdev ) {
4428 +                       mci = mcis[ i ];
4429 +                       break;
4430 +               }
4431 +       }
4432 +
4433 +       return mci;
4434 +}
4435 +
4436 +
4437 +EXPORT_SYMBOL(bluesmoke_mc_add_mc);
4438 +
4439 +/* FIXME - should a warning be printed if no error detection? correction? */
4440 +int bluesmoke_mc_add_mc(struct mem_ctl_info *mci)
4441 +{
4442 +       int i;
4443 +       int rc = 1;
4444 +
4445 +       debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
4446 +#if CONFIG_BLUESMOKE_DEBUG
4447 +#if 1 <= CONFIG_BLUESMOKE_DEBUG_VERBOSE
4448 +       bluesmoke_mc_dump_mci( mci );
4449 +#endif /* 1 <= CONFIG_BLUESMOKE_DEBUG_VERBOSE */
4450 +#if 2 <= CONFIG_BLUESMOKE_DEBUG_VERBOSE
4451 +       for ( i = 0; i < mci->nr_csrows; i++ ) {
4452 +               int j;
4453 +               bluesmoke_mc_dump_csrow( &mci->csrows[i] );
4454 +               for ( j = 0; j < mci->csrows[i].nr_channels; j++ ) {
4455 +                       bluesmoke_mc_dump_channel( &mci->csrows[i].channels[j] );
4456 +               }
4457 +       }
4458 +#endif /* 2 <= CONFIG_BLUESMOKE_DEBUG_VERBOSE */
4459 +#endif /* CONFIG_BLUESMOKE_DEBUG */
4460 +       down( &mem_ctls_mutex );
4461 +
4462 +       if ( bluesmoke_mc_find_mci_by_pdev( mci->pdev ) ) {
4463 +               printk( KERN_WARNING
4464 +                       "MC: %s (%s) %s %s already assigned %d\n",
4465 +                       mci->pdev->slot_name, pci_name(mci->pdev),
4466 +                       mci->mod_name,
4467 +                       mci->ctl_name,
4468 +                       mci->mc_idx );
4469 +               goto FINISH;
4470 +       }
4471 +
4472 +       for (i=0; i < MAX_MC_DEVICES; i++) {
4473 +               if ( ! mcis[ i ] ) break;
4474 +       }
4475 +
4476 +       if ( MAX_MC_DEVICES == i ) {
4477 +               printk( KERN_WARNING
4478 +                       "MC: out of slots in mem_ctls for %s %s\n",
4479 +                       mci->mod_name, mci->ctl_name);
4480 +               goto FINISH;
4481 +       }
4482 +
4483 +       mcis[i] = mci;
4484 +       mci->mc_idx = i;
4485 +       printk( KERN_INFO
4486 +               "MC%d: Giving out device %d to %s %s: PCI %s (%s)\n",
4487 +               mci->mc_idx,
4488 +               i, mci->mod_name, mci->ctl_name,
4489 +               mci->pdev->slot_name, pci_name(mci->pdev) );
4490 +       __module_get(THIS_MODULE);
4491 +
4492 +       /* set load time so that error rate can be tracked */
4493 +       do_gettimeofday(&mci->tv);
4494 +
4495 +#ifdef CONFIG_PROC_FS
4496 +       if ( snprintf( mci->proc_name, MC_PROC_NAME_MAX_LEN, "%d", i )
4497 +            == MC_PROC_NAME_MAX_LEN ) {
4498 +               printk( KERN_WARNING
4499 +                       "MC%d: proc entry too long for device %d \n",
4500 +                       mci->mc_idx, i );
4501 +               /* FIXME - should there be an error code and unwind? */
4502 +               goto FINISH;
4503 +       }
4504 +
4505 +       mci->proc_ent = create_proc_read_entry( mci->proc_name, 0, proc_mc,
4506 +                                               mc_read_proc, (void *)mci );
4507 +
4508 +       if ( NULL == mci->proc_ent ) {
4509 +               printk( KERN_WARNING
4510 +                       "MC%d: failed to create proc entry for controller %d \n",
4511 +                       mci->mc_idx, i );
4512 +               /* FIXME - should there be an error code and unwind? */
4513 +               goto FINISH;
4514 +       }
4515 +#endif /* CONFIG_PROC_FS */
4516 +
4517 +       rc = 0;
4518 +
4519 + FINISH:
4520 +       up( &mem_ctls_mutex );
4521 +       return rc;
4522 +}
4523 +
4524 +
4525 +EXPORT_SYMBOL(bluesmoke_mc_del_mc);
4526 +
4527 +int bluesmoke_mc_del_mc(struct mem_ctl_info *mci)
4528 +{
4529 +       int rc = 1;
4530 +       
4531 +       debugf0( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
4532 +       down( &mem_ctls_mutex );
4533 +
4534 +       if ( mcis[mci->mc_idx] != mci ) {
4535 +               printk( KERN_WARNING
4536 +                       "MC%d: index of mci for %s %s doesn't match"
4537 +                       " entry in mem_ctls\n",
4538 +                       mci->mc_idx, mci->mod_name, mci->ctl_name);
4539 +               rc = -ENODEV;
4540 +               goto FINISHED;
4541 +       }
4542 +
4543 +       mcis[mci->mc_idx] = NULL;
4544 +       module_put(THIS_MODULE);
4545 +       if ( ! module_refcount(THIS_MODULE) ) del_timer( &timer );
4546 +#ifdef CONFIG_PROC_FS
4547 +       remove_proc_entry( mci->proc_name, proc_mc );
4548 +#endif
4549 +
4550 +       printk( KERN_INFO
4551 +               "MC%d: Removed device %d for %s %s: PCI %s (%s)\n",
4552 +               mci->mc_idx, mci->mc_idx, mci->mod_name, mci->ctl_name,
4553 +               mci->pdev->slot_name, pci_name(mci->pdev) );
4554 +
4555 +       rc = 0;
4556 +
4557 + FINISHED:
4558 +       up( &mem_ctls_mutex );
4559 +       return rc;
4560 +}
4561 +
4562 +
4563 +/*
4564 + * FIXME - what happens when grain > PAGE_SIZE?
4565 + * Need multiple kmap_atomic()
4566 + */
4567 +/* FIXME - this should go in an arch dependant file */
4568 +EXPORT_SYMBOL(bluesmoke_mc_scrub_block);
4569 +
4570 +void bluesmoke_mc_scrub_block(unsigned long page, unsigned long offset, u32 size)
4571 +{
4572 +        struct page *pg;
4573 +       volatile unsigned long *virt_addr;
4574 +       int i;
4575 +
4576 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
4577 +#ifndef CONFIG_DISCONTIGMEM
4578 +       if(page > max_mapnr)
4579 +               return;         /* pointer is beyond memory, so bail */
4580 +#else
4581 +/* FIXME - use the per-pgdat data instead for discontigmem */
4582 +#endif
4583 +       pg = pfn_to_page(page);
4584 +
4585 +       virt_addr = kmap_atomic(pg, KM_BOUNCE_READ) + offset;
4586 +
4587 +       for(i = 0; i < size / sizeof(unsigned long); i++, virt_addr++) {        
4588 +               /* Very carefully read and write to memory atomically
4589 +                * so we are interrupt and smp safe.
4590 +                */
4591 +               __asm__ __volatile__(
4592 +                       "lock; addl $0, %0"
4593 +                       :: "m" (*virt_addr));
4594 +       }
4595 +       kunmap_atomic(pg, KM_BOUNCE_READ);
4596 +}
4597 +
4598 +
4599 +/* FIXME - put in a util library? */
4600 +/* FIXME - should return -1 */
4601 +EXPORT_SYMBOL(bluesmoke_mc_find_csrow_by_page);
4602 +
4603 +int bluesmoke_mc_find_csrow_by_page( struct mem_ctl_info *mci,
4604 +                                    unsigned long page )
4605 +{
4606 +       struct csrow_info *csrows = mci->csrows;
4607 +       int row = -1, i;
4608 +
4609 +       debugf1( "MC%d: " __FILE__ ": %s(): 0x%lx\n",
4610 +                mci->mc_idx, __func__, page );
4611 +
4612 +       for ( i = 0; i < mci->nr_csrows; i++ ) {
4613 +               struct csrow_info *csrow = &csrows[i];
4614 +
4615 +               if ( 0 == csrow->nr_pages ) continue;
4616 +
4617 +               debugf3( "MC%d: " __FILE__
4618 +                        ": %s(): first(0x%lx) page(0x%lx)"
4619 +                        " last(0x%lx) mask(0x%lx)\n",
4620 +                        mci->mc_idx, __func__,
4621 +                        csrow->first_page,
4622 +                        page,
4623 +                        csrow->last_page,
4624 +                        csrow->page_mask );
4625 +
4626 +               if ( ( page >= csrow->first_page )
4627 +                    && ( page <= csrow->last_page )
4628 +                    && ((page & csrow->page_mask)
4629 +                        == (csrow->first_page & csrow->page_mask)) ) {
4630 +                       row = i;
4631 +                       break;
4632 +               }
4633 +       }
4634 +
4635 +       if (row == -1) {
4636 +               printk( KERN_ERR
4637 +                       "MC%d: could not look up page error address %lx\n",
4638 +                       mci->mc_idx, (unsigned long)page);
4639 +       }
4640 +
4641 +       return row;
4642 +}
4643 +
4644 +
4645 +EXPORT_SYMBOL(bluesmoke_mc_handle_ce);
4646 +
4647 +/* FIXME - setable log (warning/emerg) levels */
4648 +/* FIXME - integrate with evlog: http://evlog.sourceforge.net/ */
4649 +void bluesmoke_mc_handle_ce(struct mem_ctl_info *mci,
4650 +                           unsigned long page_frame_number,
4651 +                           unsigned long offset_in_page,
4652 +                           unsigned long syndrome,
4653 +                           int row,
4654 +                           int channel,
4655 +                           const char *msg)
4656 +{
4657 +       unsigned long remapped_page;
4658 +
4659 +       debugf3( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
4660 +
4661 +       /* FIXME - maybe make panic on INTERNAL ERROR an option */
4662 +       if ( row >= mci->nr_csrows  || row < 0 ) {
4663 +               /* something is wrong */
4664 +               printk( KERN_ERR
4665 +                       "MC%d: INTERNAL ERROR: row out of range (%d >= %d)\n",
4666 +                       mci->mc_idx,
4667 +                       row, mci->nr_csrows );
4668 +               bluesmoke_mc_handle_ce_no_info( mci, "INTERNAL ERROR" );
4669 +               return;
4670 +       }
4671 +       if ( channel >= mci->csrows[row].nr_channels || channel < 0 ) {
4672 +               /* something is wrong */
4673 +               printk( KERN_ERR
4674 +                       "MC%d: INTERNAL ERROR: channel out of range (%d >= %d)\n",
4675 +                       mci->mc_idx,
4676 +                       channel, mci->csrows[row].nr_channels );
4677 +               bluesmoke_mc_handle_ce_no_info( mci, "INTERNAL ERROR" );
4678 +               return;
4679 +       }
4680 +
4681 +       if ( log_ce ) {
4682 +               /* FIXME - put in DIMM location */
4683 +               printk( KERN_WARNING
4684 +                       "MC%d: CE page 0x%lx, offset 0x%lx,"
4685 +                       " grain %d, syndrome 0x%lx, row %d, channel %d,"
4686 +                       " label \"%s\": %s\n",
4687 +                       mci->mc_idx,
4688 +                       page_frame_number,
4689 +                       offset_in_page,
4690 +                       mci->csrows[row].grain,
4691 +                       syndrome,
4692 +                       row,
4693 +                       channel,
4694 +                       mci->csrows[row].channels[channel].label,
4695 +                       msg );
4696 +       }
4697 +
4698 +       mci->ce_count++;
4699 +       mci->csrows[row].ce_count++;
4700 +       mci->csrows[row].channels[channel].ce_count++;
4701 +
4702 +       if ( mci->scrub_mode & SCRUB_SW_SRC ) {
4703 +               /*
4704 +                * Some MC's can remap memory so that it is still available
4705 +                * at a different address when PCI devices map into memory.
4706 +                * MC's that can't do this lose the memory where PCI devices
4707 +                * are mapped.  This mapping is MC dependant and so we call
4708 +                * back into the MC driver for it to map the MC page to
4709 +                * a physical (CPU) page which can then be mapped to a virtual
4710 +                * page - which can then be scrubbed.
4711 +                */
4712 +               if ( mci->ctl_page_to_phys ) {
4713 +                       remapped_page = mci->ctl_page_to_phys(mci,
4714 +                                                             page_frame_number);
4715 +               } else {
4716 +                       remapped_page = page_frame_number;
4717 +               }
4718 +               bluesmoke_mc_scrub_block(remapped_page,
4719 +                                        offset_in_page,
4720 +                                        mci->csrows[row].grain);
4721 +       }
4722 +}
4723 +
4724 +
4725 +EXPORT_SYMBOL(bluesmoke_mc_handle_ce_no_info);
4726 +
4727 +void bluesmoke_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg)
4728 +{
4729 +       if ( log_ce ) {
4730 +               printk( KERN_WARNING
4731 +                       "MC%d: CE - no information available: %s\n",
4732 +                       mci->mc_idx, msg );
4733 +       }
4734 +       mci->ce_noinfo_count++;
4735 +       mci->ce_count++;
4736 +}
4737 +
4738 +
4739 +EXPORT_SYMBOL(bluesmoke_mc_handle_ue);
4740 +
4741 +void bluesmoke_mc_handle_ue(struct mem_ctl_info *mci,
4742 +                           unsigned long page_frame_number,
4743 +                           unsigned long offset_in_page,
4744 +                           int row,
4745 +                           const char *msg)
4746 +{
4747 +       int len = BLUESMOKE_MC_LABEL_LEN * 4;
4748 +       char labels[len + 1];
4749 +       char *pos = labels;
4750 +       int chan;
4751 +       int chars;
4752 +
4753 +       debugf3( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
4754 +
4755 +       /* FIXME - maybe make panic on INTERNAL ERROR an option */
4756 +       if ( row >= mci->nr_csrows || row < 0 ) {
4757 +               /* something is wrong */
4758 +               printk( KERN_ERR
4759 +                       "MC%d: INTERNAL ERROR: row out of range (%d >= %d)\n",
4760 +                       mci->mc_idx,
4761 +                       row, mci->nr_csrows );
4762 +               bluesmoke_mc_handle_ue_no_info( mci, "INTERNAL ERROR" );
4763 +               return;
4764 +       }
4765 +
4766 +       chars = snprintf( pos, len + 1, "%s",
4767 +                         mci->csrows[row].channels[0].label );
4768 +       len -= chars;
4769 +       pos += chars;
4770 +       for ( chan = 1;
4771 +             (chan < mci->csrows[row].nr_channels) && (len > 0);
4772 +             chan++ ) {
4773 +               chars = snprintf( pos, len + 1, ":%s",
4774 +                                 mci->csrows[row].channels[chan].label );
4775 +               len -= chars;
4776 +               pos += chars;
4777 +       }
4778 +
4779 +       if ( log_ue ) {
4780 +               printk( KERN_EMERG
4781 +                       "MC%d: UE page 0x%lx, offset 0x%lx, grain %d, row %d,"
4782 +                       " labels \"%s\": %s\n",
4783 +                       mci->mc_idx,
4784 +                       page_frame_number,
4785 +                       offset_in_page,
4786 +                       mci->csrows[row].grain,
4787 +                       row,
4788 +                       labels,
4789 +                       msg );
4790 +       }
4791 +
4792 +       if (panic_on_ue) {
4793 +               panic( "MC%d: UE page 0x%lx, offset 0x%lx, grain %d, row %d,"
4794 +                      " labels \"%s\": %s\n",
4795 +                      mci->mc_idx,
4796 +                      page_frame_number,
4797 +                      offset_in_page,
4798 +                      mci->csrows[row].grain,
4799 +                      row,
4800 +                      labels,
4801 +                      msg );
4802 +       }
4803 +
4804 +       mci->ue_count++;
4805 +       mci->csrows[row].ue_count++;
4806 +}
4807 +
4808 +
4809 +EXPORT_SYMBOL(bluesmoke_mc_handle_ue_no_info);
4810 +
4811 +void bluesmoke_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg)
4812 +{
4813 +       if (panic_on_ue) panic("MC%d: Uncorrected Error", mci->mc_idx);
4814 +
4815 +       if ( log_ue ) {
4816 +               printk( KERN_WARNING
4817 +                       "MC%d: UE - no information available: %s\n",
4818 +                       mci->mc_idx, msg );
4819 +       }
4820 +       mci->ue_noinfo_count++;
4821 +       mci->ue_count++;
4822 +}
4823 +
4824 +
4825 +/*
4826 + * Check MC status every poll_msec.
4827 + * SMP safe, doesn't use NMI, and auto-rate-limits.
4828 + */
4829 +static void check_mc(unsigned long dummy)
4830 +{
4831 +       int i;
4832 +
4833 +       debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
4834 +
4835 +       if (in_atomic()) {
4836 +               if (down_trylock(&mem_ctls_mutex)) {
4837 +                       if (timer_pending(&timer)) {
4838 +                               mod_timer(&timer, jiffies + (HZ * poll_msec) / 1000);
4839 +                       } else {
4840 +                               timer.function = check_mc;
4841 +                               timer.expires = jiffies + (HZ * poll_msec) / 1000;
4842 +                               add_timer(&timer);
4843 +                       }
4844 +                       return;
4845 +               }
4846 +       } else 
4847 +               down(&mem_ctls_mutex);
4848 +
4849 +       for ( i = 0; i < MAX_MC_DEVICES; i++ ) {
4850 +               struct mem_ctl_info *mci = mcis[ i ];
4851 +
4852 +               if ( NULL == mci ) continue;
4853 +
4854 +               /* FIXME - should check scrub flag */
4855 +               if ( ! mci->scrub_needed 
4856 +                    && mci->edac_check ) {
4857 +                       mci->edac_check(mci);
4858 +               }
4859 +
4860 +               if ( mci->clear_err ) mci->clear_err(mci);
4861 +       }
4862 +
4863 +       if (timer_pending(&timer)) {
4864 +               mod_timer(&timer, jiffies + (HZ * poll_msec) / 1000);
4865 +       } else {
4866 +               timer.function = check_mc;
4867 +               timer.expires = jiffies + (HZ * poll_msec) /1000;
4868 +               add_timer(&timer);
4869 +       }
4870 +
4871 +       up( &mem_ctls_mutex );
4872 +}
4873 +
4874 +
4875 +int __init bluesmoke_mc_init(void)
4876 +{
4877 +       int rc = -ENODEV;
4878 +
4879 +       debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
4880 +       printk( KERN_INFO "MC: " __FILE__ " version " BLUESMOKE_MC_VER "\n" );
4881 +
4882 +       memset( mcis, 0, sizeof(mcis) );
4883 +
4884 +       check_mc(0);
4885 +
4886 +#ifdef CONFIG_PROC_FS
4887 +       if ( NULL == (proc_mc = proc_mkdir( MC_PROC_DIR, &proc_root ) ) ) {
4888 +               goto FINISHED;
4889 +       }
4890 +#endif /* CONFIG_PROC_FS */
4891 +
4892 +#ifdef CONFIG_SYSCTL
4893 +        mc_sysctl_header = register_sysctl_table(mc_root_table, 1);
4894 +#endif /* CONFIG_SYSCTL */
4895 +
4896 +       rc = 0;
4897 +
4898 + FINISHED:
4899 +       return rc;
4900 +}
4901 +
4902 +
4903 +static void __exit bluesmoke_mc_exit(void)
4904 +{
4905 +       debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
4906 +
4907 +#ifdef CONFIG_PROC_FS
4908 +       if ( proc_mc ) remove_proc_entry( MC_PROC_DIR, &proc_root );
4909 +#endif /* CONFIG_PROC_FS */
4910 +
4911 +#ifdef CONFIG_SYSCTL
4912 +        if (mc_sysctl_header) {
4913 +                unregister_sysctl_table(mc_sysctl_header);
4914 +                mc_sysctl_header = NULL;
4915 +        }
4916 +#endif /* CONFIG_SYSCTL */
4917 +}
4918 +
4919 +
4920 +module_init(bluesmoke_mc_init);
4921 +module_exit(bluesmoke_mc_exit);
4922 +
4923 +MODULE_LICENSE("GPL");
4924 +MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n"
4925 +             "Based on.work by Dan Hollis et al");
4926 +MODULE_DESCRIPTION("Core library routines for MC reporting");
4927 +
4928 +#if SCRUB
4929 +MODULE_PARM(mc_scrub, "i");
4930 +MODULE_PARM_DESC(mc_scrub, "Force MC scrubbing: 0=off 1=on");
4931 +#endif /* SCRUB */
4932 +MODULE_PARM(panic_on_ue, "i");
4933 +MODULE_PARM_DESC(panic_on_ue, "Panic on uncorrected error: 0=off 1=on");
4934 +MODULE_PARM(log_ue, "i");
4935 +MODULE_PARM_DESC(log_ue, "Log uncorrectable error to console: 0=off 1=on");
4936 +MODULE_PARM(log_ce, "i");
4937 +MODULE_PARM_DESC(log_ce, "Log correctable error to console: 0=off 1=on");
4938 +MODULE_PARM(poll_msec, "i");
4939 +MODULE_PARM_DESC(poll_msec, "Polling period in milliseconds");
4940 Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_mc.h
4941 ===================================================================
4942 --- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/bluesmoke_mc.h 1969-12-31 19:00:00.000000000 -0500
4943 +++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_mc.h      2004-12-17 12:46:23.000000000 -0500
4944 @@ -0,0 +1,435 @@
4945 +/*
4946 + * MC kernel module
4947 + * (C) 2003 Linux Networx (http://lnxi.com)
4948 + * This file may be distributed under the terms of the
4949 + * GNU General Public License.
4950 + *
4951 + * Written by Thayne Harbaugh
4952 + * Based on work by Dan Hollis <goemon at anime dot net> and others.
4953 + *     http://www.anime.net/~goemon/linux-ecc/
4954 + *
4955 + * $Id: bluesmoke_mc.h,v 1.4 2004/11/10 01:12:36 thayne Exp $
4956 + *
4957 + */
4958 +
4959 +
4960 +#ifndef _BLUESMOKE_MC_H_
4961 +#define _BLUESMOKE_MC_H_
4962 +
4963 +
4964 +#include <linux/pci.h>
4965 +#include <linux/time.h>
4966 +
4967 +
4968 +#define        BLUESMOKE_MC_VER        "MC $Revision: 1.4 $"
4969 +#define MAX_MC_DEVICES 4       /* FIXME - this should be dynamic */
4970 +#define BLUESMOKE_MC_LABEL_LEN 31
4971 +#define MC_PROC_NAME_MAX_LEN 7
4972 +
4973 +#if PAGE_SHIFT < 20
4974 +#define PAGES_TO_MiB( pages )  ( ( pages ) >> ( 20 - PAGE_SHIFT ) )
4975 +#else  /* PAGE_SHIFT > 20 */
4976 +#define PAGES_TO_MiB( pages )  ( ( pages ) << ( PAGE_SHIFT - 20 ) )
4977 +#endif
4978 +
4979 +#if defined(CONFIG_BLUESMOKE_DEBUG) \
4980 +       && defined(CONFIG_BLUESMOKE_DEBUG_VERBOSE)
4981 +#if 0 <= CONFIG_BLUESMOKE_DEBUG_VERBOSE
4982 +#define debugf0( ... ) printk( __VA_ARGS__ )
4983 +#else
4984 +#define debugf0( ... )
4985 +#endif
4986 +
4987 +#if 1 <= CONFIG_BLUESMOKE_DEBUG_VERBOSE
4988 +#define debugf1( ... ) printk( __VA_ARGS__ )
4989 +#else
4990 +#define debugf1( ... )
4991 +#endif
4992 +
4993 +#if 2 <= CONFIG_BLUESMOKE_DEBUG_VERBOSE
4994 +#define debugf2( ... ) printk( __VA_ARGS__ )
4995 +#else
4996 +#define debugf2( ... )
4997 +#endif
4998 +
4999 +#if 3 <= CONFIG_BLUESMOKE_DEBUG_VERBOSE
5000 +#define debugf3( ... ) printk( __VA_ARGS__ )
5001 +#else
5002 +#define debugf3( ... )
5003 +#endif
5004 +
5005 +#else /* !CONFIG_BLUESMOKE_DEBUG || !CONFIG_BLUESMOKE_DEBUG_VERBOSE */
5006 +
5007 +#define debugf0( ... )
5008 +#define debugf1( ... )
5009 +#define debugf2( ... )
5010 +#define debugf3( ... )
5011 +#endif /* !CONFIG_BLUESMOKE_DEBUG || !CONFIG_BLUESMOKE_DEBUG_VERBOSE */
5012
5013 +
5014 +#define bs_xstr(s) bs_str(s)
5015 +#define bs_str(s) #s
5016 +#define BS_MOD_STR bs_xstr(KBUILD_BASENAME)
5017 +
5018 +#define BIT(x) (1 << (x))
5019 +
5020 +#define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, PCI_DEVICE_ID_ ## vend ## _ ## dev
5021 +
5022 +/* memory devices */
5023 +enum dev_type {
5024 +       DEV_UNKNOWN = 0,
5025 +       DEV_X1,
5026 +       DEV_X2,
5027 +       DEV_X4,
5028 +       DEV_X8,
5029 +       DEV_X16,
5030 +       DEV_X32,        /* Do these parts exist? */
5031 +       DEV_X64         /* Do these parts exist? */
5032 +};
5033 +
5034 +#define DEV_FLAG_UNKNOWN       BIT(DEV_UNKNOWN)
5035 +#define DEV_FLAG_X1            BIT(DEV_X1)
5036 +#define DEV_FLAG_X2            BIT(DEV_X2)
5037 +#define DEV_FLAG_X4            BIT(DEV_X4)
5038 +#define DEV_FLAG_X8            BIT(DEV_X8)
5039 +#define DEV_FLAG_X16           BIT(DEV_X16)
5040 +#define DEV_FLAG_X32           BIT(DEV_X32)
5041 +#define DEV_FLAG_X64           BIT(DEV_X64)
5042 +
5043 +/* memory types */
5044 +enum mem_type {
5045 +       MEM_EMPTY = 0,  /* Empty csrow */
5046 +       MEM_RESERVED,   /* Reserved csrow type */
5047 +       MEM_UNKNOWN,    /* Unknown csrow type */
5048 +       MEM_FPM,        /* Fast page mode */
5049 +       MEM_EDO,        /* Extended data out */
5050 +       MEM_BEDO,       /* Burst Extended data out */
5051 +       MEM_SDR,        /* Single data rate SDRAM */
5052 +       MEM_RDR,        /* Registered single data rate SDRAM */
5053 +       MEM_DDR,        /* Double data rate SDRAM */
5054 +       MEM_RDDR,       /* Registered Double data rate SDRAM */
5055 +       MEM_RMBS        /* Rambus DRAM */
5056 +};
5057 +
5058 +#define MEM_FLAG_EMPTY         BIT(MEM_EMPTY)
5059 +#define MEM_FLAG_RESERVED      BIT(MEM_RESERVED)
5060 +#define MEM_FLAG_UNKNOWN       BIT(MEM_UNKNOWN)
5061 +#define MEM_FLAG_FPM           BIT(MEM_FPM)
5062 +#define MEM_FLAG_EDO           BIT(MEM_EDO)
5063 +#define MEM_FLAG_BEDO          BIT(MEM_BEDO)
5064 +#define MEM_FLAG_SDR           BIT(MEM_SDR)
5065 +#define MEM_FLAG_RDR           BIT(MEM_RDR)
5066 +#define MEM_FLAG_DDR           BIT(MEM_DDR)
5067 +#define MEM_FLAG_RDDR          BIT(MEM_RDDR)
5068 +#define MEM_FLAG_RMBS          BIT(MEM_RMBS)
5069 +
5070 +
5071 +/* chipset Error Detection and Correction capabilities and mode */
5072 +enum edac_type {
5073 +       EDAC_UNKNOWN = 0,/* Unknown if ECC is available */
5074 +       EDAC_NONE,      /* Doesnt support ECC */
5075 +       EDAC_RESERVED,  /* Reserved ECC type */
5076 +       EDAC_PARITY,    /* Detects parity errors */
5077 +       EDAC_EC,        /* Error Checking - no correction */
5078 +       EDAC_SECDED,    /* Single bit error correction, Double detection */
5079 +       EDAC_S2ECD2ED,  /* Chipkill x2 devices - do these exist? */
5080 +       EDAC_S4ECD4ED,  /* Chipkill x4 devices */
5081 +       EDAC_S8ECD8ED,  /* Chipkill x8 devices */
5082 +       EDAC_S16ECD16ED,/* Chipkill x16 devices */
5083 +};
5084 +
5085 +#define EDAC_FLAG_UNKNOWN      BIT(EDAC_UNKNOWN)
5086 +#define EDAC_FLAG_NONE         BIT(EDAC_NONE)
5087 +#define EDAC_FLAG_PARITY       BIT(EDAC_PARITY)
5088 +#define EDAC_FLAG_EC           BIT(EDAC_EC)
5089 +#define EDAC_FLAG_SECDED       BIT(EDAC_SECDED)
5090 +#define EDAC_FLAG_S2ECD2ED     BIT(EDAC_S2ECD2ED)
5091 +#define EDAC_FLAG_S4ECD4ED     BIT(EDAC_S4ECD4ED)
5092 +#define EDAC_FLAG_S8ECD8ED     BIT(EDAC_S8ECD8ED)
5093 +#define EDAC_FLAG_S16ECD16ED   BIT(EDAC_S16ECD16ED)
5094 +
5095 +
5096 +/* scrubbing capabilities */
5097 +enum scrub_type {
5098 +       SCRUB_UNKNOWN = 0,      /* Unknown if scrubber is available */
5099 +       SCRUB_NONE,             /* No scrubber */
5100 +       SCRUB_SW_PROG,          /* Software progressive (sequential) scrubbing */
5101 +       SCRUB_SW_SRC,           /* Software scrub only errors */
5102 +       SCRUB_SW_PROG_SRC,      /* Progressive software scrub from an error */
5103 +       SCRUB_SW_TUNABLE,       /* Software scrub frequency is tunable */
5104 +       SCRUB_HW_PROG,          /* Hardware progressive (sequential) scrubbing */
5105 +       SCRUB_HW_SRC,           /* Hardware scrub only errors */
5106 +       SCRUB_HW_PROG_SRC,      /* Progressive hardware scrub from an error */
5107 +       SCRUB_HW_TUNABLE        /* Hardware scrub frequency is tunable */
5108 +};
5109 +
5110 +#define SCRUB_FLAG_SW_PROG     BIT(SCRUB_SW_PROG)
5111 +#define SCRUB_FLAG_SW_SRC      BIT(SCRUB_SW_SRC_CORR)
5112 +#define SCRUB_FLAG_SW_PROG_SRC BIT(SCRUB_SW_PROG_SRC_CORR)
5113 +#define SCRUB_FLAG_SW_TUN      BIT(SCRUB_SW_SCRUB_TUNABLE)
5114 +#define SCRUB_FLAG_HW_PROG     BIT(SCRUB_HW_PROG)
5115 +#define SCRUB_FLAG_HW_SRC      BIT(SCRUB_HW_SRC_CORR)
5116 +#define SCRUB_FLAG_HW_PROG_SRC BIT(SCRUB_HW_PROG_SRC_CORR)
5117 +#define SCRUB_FLAG_HW_TUN      BIT(SCRUB_HW_TUNABLE)
5118 +
5119 +
5120 +/* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */
5121 +
5122 +
5123 +/*
5124 + * There are several things to be aware of that aren't at all obvious:
5125 + *
5126 + *
5127 + * SOCKETS, SOCKET SETS, BANKS, ROWS, CHIP-SELECT ROWS, CHANNELS, etc..
5128 + *
5129 + * These are some of the many terms that are thrown about that don't always
5130 + * mean what people think they mean (Inconceivable!).  In the interest of
5131 + * creating a common ground for discussion, terms and their definitions
5132 + * will be established.
5133 + *
5134 + * Memory devices:     The individual chip on a memory stick.  These devices
5135 + *                     commonly output 4 and 8 bits each.  Grouping several
5136 + *                     of these in parallel provides 64 bits which is common
5137 + *                     for a memory stick.
5138 + *
5139 + * Memory Stick:       A printed circuit board that agregates multiple
5140 + *                     memory devices in parallel.  This is the atomic
5141 + *                     memory component that is purchaseable by Joe consumer
5142 + *                     and loaded int a memory socket.
5143 + *
5144 + * Socket:             A physical connector on the motherboard that accepts
5145 + *                     a single memory stick.
5146 + *
5147 + * Channel:            Set of memory devices on a memory stick that must be
5148 + *                     grouped in parallel with one or more additional
5149 + *                     channels from other memory sticks.  This parallel
5150 + *                     grouping of the output from multiple channels are
5151 + *                     necessary for the smallest granularity of memory access.
5152 + *                     Some memory controllers are capable of single channel -
5153 + *                     which means that memory sticks can be loaded
5154 + *                     individually.  Other memory controllers are only
5155 + *                     capable of dual channel - which means that memory
5156 + *                     sticks must be loaded as pairs (see "socket set").
5157 + *
5158 + * Chip-select row:    All of the memory devices that are selected together.
5159 + *                     for a single, minimum grain of memory access.
5160 + *                     This selects all of the parallel memory devices across
5161 + *                     all of the parallel channels.  Common chip-select rows
5162 + *                     for single channel are 64 bits, for dual channel 128
5163 + *                     bits.
5164 + *
5165 + * Double-sided stick: A double-sided stick has two chip-select rows which
5166 + *                     access different sets of memory devices.  The two
5167 + *                     rows cannot be accessed concurrently.  "Double-sided"
5168 + *                     is irrespective of the memory devices being mounted
5169 + *                     on both sides of the memory stick.
5170 + *
5171 + * Socket set:         All of the memory sticks that are required for for
5172 + *                     a single memory access or all of the memory sticks
5173 + *                     spanned by a chip-select row.  A single socket set
5174 + *                     has two chip-select rows if double-sided sticks are
5175 + *                     used.
5176 + *
5177 + * Bank:               This term is avoided because it is unclear when
5178 + *                     needing to distinguish between chip-select rows and
5179 + *                     socket sets.
5180 + *
5181 + *
5182 + * Controller pages:
5183 + *
5184 + * Physical pages:
5185 + *
5186 + * Virtual pages:
5187 + *
5188 + *
5189 + * STRUCTURE ORGANIZATION AND CHOICES
5190 + *
5191 + * 
5192 + *
5193 + * PS - I enjoyed writing all that about as much as you enjoyed reading it.
5194 + */
5195 +
5196 +
5197 +struct channel_info {
5198 +       int chan_idx;           /* channel index */
5199 +       u32 ce_count;   /* Correctable Errors for this CHANNEL */
5200 +       char label[BLUESMOKE_MC_LABEL_LEN + 1]; /* DIMM label on motherboard */
5201 +       struct csrow_info *csrow;/* the parent */
5202 +};
5203 +
5204 +
5205 +struct csrow_info {
5206 +       unsigned long first_page;/* first page number in dimm */
5207 +       unsigned long last_page;/* last page number in dimm */
5208 +       unsigned long page_mask;/* used for interleaving - 0UL for non intlv */
5209 +       u32 nr_pages;   /* number of pages in csrow */
5210 +       u32 grain;              /* granularity of reported error in bytes */
5211 +       int csrow_idx;          /* the chip-select row */
5212 +       enum dev_type dtype;    /* memory device type */ 
5213 +       u32 ue_count;   /* Uncorrectable Errors for this csrow */
5214 +       u32 ce_count;   /* Correctable Errors for this csrow */
5215 +       enum mem_type mtype;    /* memory csrow type */
5216 +       enum edac_type edac_mode;/* EDAC mode for this csrow */
5217 +       struct mem_ctl_info *mci;/* the parent */
5218 +       /* FIXME the number of CHANNELs might need to become dynamic */
5219 +       u32 nr_channels;
5220 +       struct channel_info *channels;
5221 +};
5222 +
5223 +
5224 +typedef void *pvt_info_t;
5225 +
5226 +
5227 +struct mem_ctl_info {
5228 +       unsigned long mtype_cap;/* memory types supported by mc */
5229 +       unsigned long edac_ctl_cap;/* Memory controller EDAC capabilities */
5230 +       unsigned long edac_cap; /* configuration capabilities - this is
5231 +                                  closely related to edac_ctl_cap.  The
5232 +                                  difference is that the controller
5233 +                                  may be capable of s4ecd4ed which would
5234 +                                  be listed in edac_ctl_cap, but if
5235 +                                  channels aren't capable of s4ecd4ed then the
5236 +                                  edac_cap would not have that capability. */
5237 +       unsigned long scrub_cap;/* chipset scrub capabilities */
5238 +       enum scrub_type scrub_mode;/* current scrub mode */
5239 +       /* pointer to edac checking routine */
5240 +       void (*edac_check)(struct mem_ctl_info *mci);
5241 +       /* pointer to error clear routine */
5242 +       void (*clear_err)(struct mem_ctl_info *mci);
5243 +       /*
5244 +        * Remaps memory pages: controller pages to physical pages.
5245 +        * For most MC's, this will be NULL.
5246 +        */
5247 +       /* FIXME - why not send the phys page to begin with? */
5248 +       unsigned long (*ctl_page_to_phys)(struct mem_ctl_info *mci,
5249 +                                         unsigned long page);
5250 +       int mc_idx;
5251 +       int nr_csrows;
5252 +       struct csrow_info *csrows;
5253 +       /*
5254 +        * FIXME - what about controllers on other busses? - IDs must be
5255 +        * unique.  pdev pointer should be sufficiently unique, but
5256 +        * BUS:SLOT.FUNC numbers may not be unique.
5257 +        */
5258 +       struct pci_dev *pdev;
5259 +       const char *mod_name;
5260 +       const char *mod_ver;
5261 +       const char *ctl_name;
5262 +       char proc_name[MC_PROC_NAME_MAX_LEN + 1];
5263 +#ifdef CONFIG_PROC_FS
5264 +       struct proc_dir_entry *proc_ent;
5265 +#endif
5266 +       pvt_info_t pvt_info;
5267 +       int scrub_needed;
5268 +       u32 ue_noinfo_count;    /* Uncorrectable Errors w/o info */
5269 +       u32 ce_noinfo_count;    /* Correctable Errors w/o info */
5270 +       u32 ue_count;   /* Total Uncorrectable Errors for this MC */
5271 +       u32 ce_count;   /* Total Correctable Errors for this MC */
5272 +       struct timeval tv;      /* time when counters were zeroed */
5273 +};
5274 +
5275 +
5276 +/* write all or some bits in a byte-register*/
5277 +static inline void pci_write_bits8( struct pci_dev *pdev, int offset,
5278 +                                   u8 value, u8 mask )
5279 +{ 
5280 +       if ( mask != 0xff ){
5281 +               u8 buf;
5282 +               pci_read_config_byte( pdev, offset, &buf);
5283 +               value &= mask;
5284 +               buf &= ~mask;
5285 +               value |= buf;
5286 +       }
5287 +       pci_write_config_byte( pdev, offset, value );
5288 +}  
5289 +
5290 +
5291 +/* write all or some bits in a word-register*/
5292 +static inline void pci_write_bits16( struct pci_dev *pdev, int offset,
5293 +                                    u16 value, u16 mask )
5294 +{ 
5295 +       if ( mask != 0xffff ){
5296 +               u16 buf;
5297 +               pci_read_config_word( pdev, offset, &buf );
5298 +               value &= mask;
5299 +               buf &= ~mask;
5300 +               value |= buf;
5301 +       }
5302 +       pci_write_config_word( pdev, offset, value);
5303 +}  
5304 +
5305 +
5306 +/* write all or some bits in a dword-register*/
5307 +static inline void pci_write_bits32( struct pci_dev *pdev, int offset,
5308 +                                    u32 value, u32 mask )
5309 +{ 
5310 +       if ( mask != 0xffff ){
5311 +               u32 buf;
5312 +               pci_read_config_dword( pdev, offset, &buf );
5313 +               value &= mask;
5314 +               buf &= ~mask;
5315 +               value |= buf;
5316 +       }
5317 +       pci_write_config_dword( pdev, offset, value );
5318 +}  
5319 +
5320 +
5321 +#if CONFIG_BLUESMOKE_DEBUG
5322 +void bluesmoke_mc_dump_channel( struct channel_info *chan );
5323 +void bluesmoke_mc_dump_mci( struct mem_ctl_info *mci );
5324 +void bluesmoke_mc_dump_csrow( struct csrow_info *csrow );
5325 +#endif /* CONFIG_BLUESMOKE_DEBUG */
5326 +
5327 +extern int bluesmoke_mc_add_mc(struct mem_ctl_info *mci);
5328 +extern int bluesmoke_mc_del_mc(struct mem_ctl_info *mci);
5329 +
5330 +extern int bluesmoke_mc_find_csrow_by_page( struct mem_ctl_info *mci,
5331 +                                           unsigned long page );
5332 +
5333 +extern struct mem_ctl_info *bluesmoke_mc_find_mci_by_pdev(struct pci_dev *pdev );
5334 +
5335 +extern void bluesmoke_mc_scrub_block(unsigned long page,
5336 +                                    unsigned long offset,
5337 +                                    u32 size);
5338 +
5339 +/*
5340 + * The no info errors are used when error overflows are reported.
5341 + * There are a limited number of error logging registers that can
5342 + * be exausted.  When all registers are exhausted and an additional
5343 + * error occurs then an error overflow register records that an
5344 + * error occured and the type of error, but doesn't have any
5345 + * further information.  The ce/ue versions make for cleaner
5346 + * reporting logic and function interface - reduces conditional
5347 + * statement clutter and extra function arguments.
5348 + */
5349 +extern void bluesmoke_mc_handle_ce(struct mem_ctl_info *mci,
5350 +                                  unsigned long page_frame_number,
5351 +                                  unsigned long offset_in_page,
5352 +                                  unsigned long syndrome,
5353 +                                  int row,
5354 +                                  int channel,
5355 +                                  const char *msg);
5356 +
5357 +extern void bluesmoke_mc_handle_ce_no_info(struct mem_ctl_info *mci,
5358 +                                          const char *msg);
5359 +
5360 +extern void bluesmoke_mc_handle_ue(struct mem_ctl_info *mci,
5361 +                                  unsigned long page_frame_number,
5362 +                                  unsigned long offset_in_page,
5363 +                                  int row,
5364 +                                  const char *msg);
5365 +
5366 +extern void bluesmoke_mc_handle_ue_no_info(struct mem_ctl_info *mci,
5367 +                                          const char *msg);
5368 +
5369 +/*
5370 + * This kmalloc's and initializes all the structures.
5371 + * Can't be used if all structures don't have the same lifetime.
5372 + */
5373 +extern struct mem_ctl_info *bluesmoke_mc_init_structs(u32 sz_pvt,
5374 +                                                     u32 nr_csrows,
5375 +                                                     u32 nr_chans);
5376 +
5377 +#include "compatmac.h"
5378 +
5379 +#endif /* _BLUESMOKE_MC_H_ */
5380 Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/compatmac.h
5381 ===================================================================
5382 --- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/compatmac.h    1969-12-31 19:00:00.000000000 -0500
5383 +++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/compatmac.h 2004-12-17 12:46:23.000000000 -0500
5384 @@ -0,0 +1,63 @@
5385 +#ifndef __LINUX_BLUESMOKE_COMPATMAC_H__
5386 +#define __LINUX_BLUESMOKE_COMPATMAC_H__
5387 +
5388 +#include <linux/version.h>
5389 +#include <linux/pci.h>
5390 +
5391 +/*
5392 + * Assume that if the kernel isn't 2.6.x then it is a 2.4.x - this will
5393 + * obviously break 2.5.x but we don't care!
5394 + */
5395 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
5396 +
5397 +#define pci_name(pci_dev)              ((pci_dev)->slot_name)
5398 +
5399 +#ifndef pci_pretty_name
5400 +# define pci_pretty_name(pdev) ""
5401 +#endif
5402 +
5403 +#define try_module_get(m) try_inc_mod_count(m)
5404 +#define __module_get(m) do { if (!try_inc_mod_count(m)) BUG(); } while(0)
5405 +#define module_put(m) do { if (m) __MOD_DEC_USE_COUNT((struct module *)(m)); } while(0)
5406 +#define module_refcount(m) (MOD_IN_USE)
5407 +#define set_module_owner(x) do { x->owner = THIS_MODULE; } while(0)
5408 +
5409 +
5410 +/*
5411 + * The real pci_scan_single_device() in the 2.6.x series
5412 + * has a few more features.  It calls pci_name_device() and
5413 + * pci_fixup_device().  Unfortunately neither of those are
5414 + * exported symbols.  The pci_name is a nicety that we can
5415 + * live without.  As far as pci quirks, if your device has them
5416 + * then you better just fix them in your driver rather than
5417 + * trying to call some generic kernel code.
5418 + */
5419 +static inline struct pci_dev *pci_scan_single_device( struct pci_bus *bus,
5420 +                                                     int devfn )
5421 +{
5422 +               struct pci_dev tmp_pdev, *pdev = NULL;
5423 +
5424 +               memset( &tmp_pdev, 0, sizeof(tmp_pdev) );
5425 +               tmp_pdev.bus = bus;
5426 +               tmp_pdev.devfn = devfn;
5427 +               if ( (pdev = pci_scan_device( &tmp_pdev ) ) ) {
5428 +                       pci_insert_device( pdev, bus );
5429 +               }
5430 +               return pdev;
5431 +}
5432 +
5433 +
5434 +#else
5435 +
5436 +#ifndef pci_pretty_name
5437 +# define pci_pretty_name(pdev) ((pdev)->pretty_name)
5438 +#endif
5439 +
5440 +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) */
5441 +
5442 +#ifndef in_atomic
5443 +#define in_atomic() 0
5444 +#define down_trylock(mtx) 1
5445 +#endif /* in_atomic */
5446 +
5447 +#endif /* __LINUX_BLUESMOKE_COMPATMAC_H__ */
5448 Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/linux/pci_ids.h
5449 ===================================================================
5450 --- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/linux/pci_ids.h  2004-11-11 10:28:34.000000000 -0500
5451 +++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/linux/pci_ids.h       2004-12-17 12:45:23.000000000 -0500
5452 @@ -454,6 +454,10 @@
5453  #define PCI_DEVICE_ID_AMI_MEGARAID2    0x9060
5454  
5455  #define PCI_VENDOR_ID_AMD              0x1022
5456 +#define PCI_DEVICE_ID_AMD_OPT_0_HT     0x1100
5457 +#define PCI_DEVICE_ID_AMD_OPT_1_ADDRMAP        0x1101
5458 +#define PCI_DEVICE_ID_AMD_OPT_2_MEMCTL 0x1102
5459 +#define PCI_DEVICE_ID_AMD_OPT_3_MISCCTL        0x1103
5460  #define PCI_DEVICE_ID_AMD_LANCE                0x2000
5461  #define PCI_DEVICE_ID_AMD_LANCE_HOME   0x2001
5462  #define PCI_DEVICE_ID_AMD_SCSI         0x2020
5463 @@ -2078,6 +2082,22 @@
5464  #define PCI_DEVICE_ID_INTEL_82801EB_7  0x24d7
5465  #define PCI_DEVICE_ID_INTEL_82801EB_11 0x24db
5466  #define PCI_DEVICE_ID_INTEL_82801EB_13 0x24dd
5467 +#define PCI_DEVICE_ID_INTEL_7205_0     0x255d
5468 +#define PCI_DEVICE_ID_INTEL_7205_1_ERR 0x2551
5469 +#define PCI_DEVICE_ID_INTEL_7500_0     0x2540
5470 +#define PCI_DEVICE_ID_INTEL_7500_1_ERR 0x2541
5471 +#define PCI_DEVICE_ID_INTEL_7501_0     0x254c
5472 +#define PCI_DEVICE_ID_INTEL_7501_1_ERR 0x2541
5473 +#define PCI_DEVICE_ID_INTEL_7505_0     0x2550
5474 +#define PCI_DEVICE_ID_INTEL_7505_1_ERR 0x2551
5475 +#define PCI_DEVICE_ID_INTEL_7520_0      0x3590
5476 +#define PCI_DEVICE_ID_INTEL_7520_1_ERR  0x3591
5477 +#define PCI_DEVICE_ID_INTEL_ICH5R_D30_F0  0x244e
5478 +#define PCI_DEVICE_ID_INTEL_ICH5R_D31_F0  0x24D0
5479 +#define PCI_DEVICE_ID_INTEL_82875_0    0x2578
5480 +#define PCI_DEVICE_ID_INTEL_82875_6    0x257e
5481 +#define PCI_DEVICE_ID_INTEL_7520_0     0x3590
5482 +#define PCI_DEVICE_ID_INTEL_7520_1_ERR 0x3591
5483  #define PCI_DEVICE_ID_INTEL_ESB_0      0x25a0
5484  #define PCI_DEVICE_ID_INTEL_ESB_1      0x25a1
5485  #define PCI_DEVICE_ID_INTEL_ESB_2      0x25a2