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
7 source "drivers/mtd/Kconfig"
9 +source "drivers/bluesmoke/Kconfig"
11 source "drivers/parport/Kconfig"
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
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
33 +# Copyright (c) 2003 Linux Networx
34 +# Licensed and distributed under the GPL
36 +# $Id: Kconfig,v 1.4 2004/11/10 01:12:35 thayne Exp $
39 +menu 'Bluesmoke - error detection and reporting (RAS)'
42 + tristate "Bluesmoke core system error reporting"
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'.
50 +comment "Reporting subsystems"
51 + depends on BLUESMOKE
53 +config BLUESMOKE_DEBUG
55 + depends on BLUESMOKE
57 + This turns on debugging information for the entire Bluesmoke
58 + sub-system. Usually you should select 'N'.
60 +config BULESMOKE_DEBUG_VERBOSE
61 + int "Debugging verbosity (0=quiet, 3=noisy)"
62 + depends on BLUESMOKE_DEBUG
65 + Verbosity level of Bluesmoke debug messages.
67 +config BLUESMOKE_MM_EDAC
68 + tristate "Bluesmoke Main Memory EDAC (Error Detection And Correction) reporting"
69 + depends on BLUESMOKE
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'.
79 +comment "Bluesmoke system controller/chipset support"
80 + depends on BLUESMOKE
82 +config BLUESMOKE_AMD76X
83 + tristate "AMD 76x (760, 762, 768)"
84 + depends on BLUESMOKE
86 +config BLUESMOKE_E7XXX
87 + tristate "Intel e7xxx (e7205, e7500, e7501, e7505)"
88 + depends on BLUESMOKE
90 +config BLUESMOKE_E752X
91 + tristate "Intel e752x (e7520)"
92 + depends on BLUESMOKE
94 +config BLUESMOKE_I82875P
95 + tristate "Intel 82875p"
96 + depends on BLUESMOKE
99 + tristate "AMD K8 (Athlon FX, Athlon 64, Opteron)"
100 + depends on BLUESMOKE
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
109 +# Makefile for the Linux kernel bluesmoke drivers.
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.
115 +# $Id: Makefile,v 1.4 2004/11/10 01:12:35 thayne Exp $
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
125 +ifeq ($(PATCHLEVEL),4)
127 +export-objs := bluesmoke_mc.o
129 +O_TARGET := bluesmokelink.o
131 +include $(TOPDIR)/Rules.make
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
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.
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/
149 + * $Id: bluesmoke_amd76x.c,v 1.4 2004/11/10 01:12:35 thayne Exp $
154 +#include <linux/config.h>
155 +#include <linux/module.h>
156 +#include <linux/init.h>
158 +#include <linux/pci.h>
159 +#include <linux/pci_ids.h>
161 +#include <linux/slab.h>
163 +#include "bluesmoke_mc.h"
166 +#define AMD76X_NR_CSROWS 8
167 +#define AMD76X_NR_CHANS 1
168 +#define AMD76X_NR_DIMMS 4
171 +/* AMD 76x register addresses - device 0 function 0 - PCI bridge */
172 +#define AMD76X_ECC_MODE_STATUS 0x48 /* Mode and status of ECC (32b)
175 + * 15:14 SERR enabled: x1=ue 1x=ce
177 + * 12 diag: disabled, enabled
178 + * 11:10 mode: dis, EC, ECC, ECC+scrub
179 + * 9:8 status: x1=ue 1x=ce
183 +#define AMD76X_DRAM_MODE_STATUS 0x58 /* DRAM Mode and status (32b)
185 + * 31:26 clock disable 5 - 0
188 + * 23 mode register service
189 + * 22:21 suspend to RAM
190 + * 20 burst refresh enable
191 + * 19 refresh disable
193 + * 17:16 cycles-per-refresh
195 + * 7:0 x4 mode enable 7 - 0
197 +#define AMD76X_MEM_BASE_ADDR 0xC0 /* Memory base address (8 x 32b)
199 + * 31:23 chip-select base
201 + * 15:7 chip-select mask
204 + * 0 chip-select enable
214 +struct amd76x_dev_info {
215 + const char *ctl_name;
219 +static const struct amd76x_dev_info amd76x_devs[] = {
221 + .ctl_name = "AMD761"
224 + .ctl_name = "AMD762"
229 +static void amd76x_check(struct mem_ctl_info *mci)
233 + debugf1( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
235 + pci_read_config_dword(mci->pdev, AMD76X_ECC_MODE_STATUS, &ems);
237 + if ( ems & BIT(8) ) { /* UE? */
238 + u32 ems_ue_row = (ems >> 4) & 0xf;
240 + pci_write_bits32( mci->pdev, AMD76X_ECC_MODE_STATUS,
241 + (u32)BIT(8), (u32)BIT(8) );
243 + bluesmoke_mc_handle_ue( mci, mci->csrows[ems_ue_row].first_page,
244 + 0, ems_ue_row, mci->ctl_name );
247 + if ( ems & BIT(9) ) { /* CE? */
248 + u32 ems_ce_row = ems & 0xf;
250 + pci_write_bits32( mci->pdev, AMD76X_ECC_MODE_STATUS,
251 + (u32)BIT(9), (u32)BIT(9) );
253 + bluesmoke_mc_handle_ce( mci, mci->csrows[ems_ce_row].first_page,
254 + 0, 0, ems_ce_row, 0, mci->ctl_name );
260 +static int amd76x_probe1( struct pci_dev *pdev, int dev_idx )
264 + struct mem_ctl_info *mci = NULL;
265 + enum edac_type ems_modes[] = { EDAC_NONE,
272 + debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
274 + pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS, &ems);
275 + ems_mode = ( ems >> 10 ) & 0x3;
277 + mci = bluesmoke_mc_init_structs(0,
283 + goto FAIL_FINISHED;
286 + debugf0( "MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci );
289 + mci->mtype_cap = MEM_FLAG_RDDR;
291 + mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
293 + mci->edac_cap = EDAC_FLAG_EC | EDAC_FLAG_SECDED;
295 + mci->edac_cap = EDAC_FLAG_NONE;
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;
305 + for ( index = 0; index < mci->nr_csrows; index++ ) {
306 + struct csrow_info *csrow = &mci->csrows[ index ];
312 + /* find the DRAM Chip Select Base address and mask */
313 + pci_read_config_dword( mci->pdev,
314 + AMD76X_MEM_BASE_ADDR + (index*4),
317 + if ( ! (mba & BIT(0)) ) {
321 + mba_base = mba & 0xff800000UL;
322 + mba_mask = ((mba & 0xff80) << 16) | 0x7fffffUL;
324 + pci_read_config_dword( mci->pdev,
325 + AMD76X_DRAM_MODE_STATUS,
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 ];
338 + /* clear counters */
339 + pci_write_bits32( mci->pdev, AMD76X_ECC_MODE_STATUS,
340 + (u32)(0x3 << 8), (u32)(0x3 << 8) );
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;
348 + /* get this far and it's successful */
349 + debugf3( "MC: " __FILE__ ": %s(): success\n", __func__ );
365 +static int amd76x_suspend (struct pci_dev *pdev, u32 state)
367 + debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
373 +static int amd76x_resume (struct pci_dev *pdev)
375 + debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
380 +#endif /* CONFIG_PM */
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 )
387 + debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
389 + /* don't need to call pci_device_enable() */
390 + return amd76x_probe1( pdev, ent->driver_data );
394 +static void __devexit amd76x_remove_one( struct pci_dev *pdev )
396 + struct mem_ctl_info *mci;
398 + debugf0( __FILE__ ": %s()\n", __func__);
400 + if ( NULL == ( mci = bluesmoke_mc_find_mci_by_pdev( pdev ) ) ) {
404 + if ( 0 != bluesmoke_mc_del_mc( mci ) ) {
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. */
421 +MODULE_DEVICE_TABLE(pci, amd76x_pci_tbl);
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,
430 + .suspend = amd76x_suspend,
431 + .resume = amd76x_resume,
432 +#endif /* CONFIG_PM */
436 +int __init amd76x_init(void)
440 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
441 + pci_rc = pci_module_init( &amd76x_driver );
442 + if ( pci_rc < 0 ) return pci_rc;
448 +static void __exit amd76x_exit(void)
450 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
451 + pci_unregister_driver( &amd76x_driver );
455 +module_init(amd76x_init);
456 +module_exit(amd76x_exit);
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
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.
473 + * See "enum e752x_chips" below for supported chipsets
475 + * Written by Tom Zimmerman
478 + * Thayne Harbaugh (Linux Networx)
480 + * $Id: bluesmoke_e752x.c,v 1.5 2004/11/18 22:19:46 thayne Exp $
485 +#include <linux/config.h>
486 +#include <linux/module.h>
487 +#include <linux/init.h>
489 +#include <linux/pci.h>
490 +#include <linux/pci_ids.h>
492 +#include <linux/slab.h>
494 +#include "bluesmoke_mc.h"
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 */
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 */
506 +#define E752X_NR_CSROWS 8 /* number of csrows */
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) */
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
523 +#define E752X_DRC 0x7C /* DRAM controller mode reg (32b) */
525 + * 22 Number channels 0=1,1=2
526 + * 19:18 DRB Granularity 32/64MB
528 +#define E752X_DRM 0x80 /* Dimm mapping register */
529 +#define E752X_DDRCSR 0x9A /* DDR control and status reg (16b) */
531 + * 14:12 1 single A, 2 single B, 3 dual
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) */
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) */
562 + * 30:2 CE address (64 byte block 34:6)
566 +#define E752X_DRAM_CELOG2_ADD 0xC8 /* DRAM first correctable memory */
567 + /* error address register (32b) */
570 + * 30:2 CE address (64 byte block 34:6)
574 +#define E752X_DRAM_UELOG_ADD 0xA4 /* DRAM first uncorrectable memory */
575 + /* error address register (32b) */
578 + * 30:2 CE address (64 byte block 34:6)
582 +#define E752X_DRAM_UELOGS_ADD 0xA8 /* DRAM first uncorrectable scrub memory */
583 + /* error address register (32b) */
586 + * 30:2 CE address (64 byte block 34:6)
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) */
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) */
607 + struct pci_dev *bridge_ck;
608 + struct pci_dev *dev_d0f0;
609 + struct pci_dev *dev_d0f1;
616 + const struct e752x_dev_info *dev_info;
620 +struct e752x_dev_info {
622 + const char *ctl_name;
626 +static const struct e752x_dev_info e752x_devs[] = {
628 + .err_dev = PCI_DEVICE_ID_INTEL_7520_1_ERR,
629 + .ctl_name = "E7520"
634 +/* FIXME - is this valid for both SECDED and S4ECD4ED? */
635 +static inline int e752x_find_channel(u16 syndrome)
637 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
639 + if((syndrome & 0xff00)==0)
641 + if((syndrome & 0x00ff)==0)
643 + if((syndrome & 0xf000)==0)
645 + if((syndrome & 0x0f00)==0)
651 +static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
652 + unsigned long page)
655 + struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
657 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
659 + if(page < pvt->tolm)
661 + if((page >= 0x100000)&&(page < pvt->remapbase))
663 + remap = (page - pvt->tolm) + pvt->remapbase;
664 + if(remap < pvt->remaplimit)
666 + printk(KERN_ERR "Invalid page %lx - out of range\n", page);
667 + return(pvt->tolm-1);
671 +static void process_ce(struct mem_ctl_info *mci, u16 error_one,
672 + u32 celog1_add, u16 celog1_syndrome)
674 + u32 error_1b, page;
679 + struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
681 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
683 + if(error_one&0x0101) {
684 + /* read the error address */
685 +// pci_read_config_dword(pvt->bridge_ck,E752X_DRAM_CELOG1_ADD,
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,
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]);
701 + /* test for channel remapping */
703 + if(pvt->map[i] == row)
706 + printk( KERN_WARNING
707 + "Test computed row %d\n",i);
712 + printk( KERN_WARNING
713 + "MC%d: row %d not found in remap table\n",
719 + row = bluesmoke_mc_find_csrow_by_page( mci, page );
722 + channel = 0; /* 0 = channel A */
724 + channel = 1; /* 1 = channel B */
728 + bluesmoke_mc_handle_ce( mci, page, 0, syndrome,
729 + row, channel, "e752x CE" );
734 +static void process_ue(struct mem_ctl_info *mci, u16 error_one,
735 + u32 uelog_add, u32 uelogs_add)
737 + u32 error_2b, block_page;
739 + struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
741 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
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);
752 + row = bluesmoke_mc_find_csrow_by_page(mci, block_page);
754 + bluesmoke_mc_handle_ue( mci, block_page, 0, row,
755 + "e752x UE from Read" );
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);
766 + row = bluesmoke_mc_find_csrow_by_page(mci, block_page);
768 + bluesmoke_mc_handle_ue( mci, block_page, 0, row,
769 + "e752x UE from Scruber" );
774 +static void process_ue_no_info(struct mem_ctl_info *mci)
776 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
778 + bluesmoke_mc_handle_ue_no_info( mci, "e752x UE log register overflow" );
782 +static void process_ue_no_info_wr(struct mem_ctl_info *mci)
784 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
786 + bluesmoke_mc_handle_ue_no_info( mci, "e752x UE log memory write" );
789 +static void process_ded_retry(struct mem_ctl_info *mci,u16 error,u32 retry_add)
791 + u32 error_1b, page;
793 + struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
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 */
800 + row = bluesmoke_mc_find_csrow_by_page( mci, page );
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);
807 +static void process_threshold_ce(struct mem_ctl_info *mci,u16 error)
809 + printk( KERN_WARNING
810 + "MC%d: Memory threshold CE\n",mci->mc_idx);
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 "};
819 +static void global_error(int fatal, u32 errors)
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]);
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"};
837 +static void hub_error(int fatal, u8 errors)
842 + if(errors & (1<<i)) {
843 + printk( KERN_WARNING "%sError %s\n",
844 + fatal_message[fatal],
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"};
855 +static void membuf_error(u8 errors)
860 + if(errors & (1<<i)) {
861 + printk( KERN_WARNING "Non-Fatal Error %s\n",
862 + membuf_message[i]);
867 +char *sysbus_message[10]= {"Addr or Request Parity",
868 + "Data Strobe Glitch",
869 + "Addr Strobe Glitch",
872 + "Non DRAM Lock Error",
875 + "IO Subsystem Parity"};
877 +static void sysbus_error(int fatal, u32 errors)
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]);
890 +static void e752x_check(struct mem_ctl_info *mci)
894 + u16 error_one, error_next, stat;
895 + u32 stat32,error32;
896 + /* Snap shot of error registers */
907 + u16 celog1_syndrome;
908 + u16 celog2_syndrome;
912 + struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
913 + struct pci_dev *pres_dev;
914 + struct pci_dev *dev;
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__ );
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 */
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);
933 + printk("\n%2.2x ",i);
935 + printk("%2.2x ",stat8);
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);
943 + printk("\n%2.2x ",i);
945 + printk("%2.2x ",stat8);
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,
956 + pci_read_config_word(dev,E752X_DRAM_CELOG1_SYNDROME,
958 + pci_read_config_dword(dev,E752X_DRAM_UELOG_ADD,
960 + pci_read_config_dword(dev,E752X_DRAM_UELOGS_ADD,
962 + pci_read_config_dword(dev,E752X_DRAM_RETRY_ADD,
965 + pci_write_config_dword(dev,E752X_FERR_GLOBAL,stat32);
966 + error32=(stat32>>18)&0x3ff;
967 + stat32=(stat32>>4)&0x7ff;
969 + global_error(1,error32);
971 + global_error(0,stat32);
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,
983 + pci_read_config_word(dev,E752X_DRAM_CELOG2_SYNDROME,
986 + pci_write_config_dword(dev,E752X_NERR_GLOBAL,stat32);
987 + error32=(stat32>>18)&0x3ff;
988 + stat32=(stat32>>4)&0x7ff;
990 + global_error(1,error32);
992 + global_error(0,stat32);
995 +// pci_read_config_byte(dev,E752X_HI_FERR,&stat8);
997 + if(stat8&0x7f) { /* Error, so process */
998 + pci_write_config_dword(dev,E752X_HI_FERR,stat8);
1001 + hub_error(1,(stat8&0x2b));
1003 + hub_error(0,(stat8&0x54));
1005 +// pci_read_config_byte(dev,E752X_HI_NERR,&stat8);
1007 + if(stat8&0x7f) { /* Error, so process */
1008 + pci_write_config_dword(dev,E752X_HI_NERR,stat8);
1011 + hub_error(1,(stat8&0x2b));
1013 + hub_error(0,(stat8&0x54));
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));
1030 +// pci_read_config_byte(dev,E752X_BUF_FERR,&stat8);
1032 + if(stat8&0x0f) { /* Error, so process */
1033 + pci_write_config_dword(dev,E752X_BUF_FERR,stat8);
1035 + membuf_error(stat8);
1037 +// pci_read_config_byte(dev,E752X_BUF_NERR,&stat8);
1039 + if(stat8&0x0f) { /* Error, so process */
1040 + pci_write_config_dword(dev,E752X_BUF_NERR,stat8);
1042 + membuf_error(stat8);
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 */
1054 + pci_write_bits16(pvt->bridge_ck, E752X_DRAM_FERR,
1055 + error_one,error_one);
1058 + pci_write_bits16(pvt->bridge_ck, E752X_DRAM_NERR,
1059 + error_next, error_next);
1062 + /* decode and report errors */
1063 + if(error_one & 0x0101) { /* check first error correctable */
1064 + process_ce(mci,error_one,celog1_add,celog1_syndrome);
1066 + if(error_next & 0x0101) { /* check next error correctable */
1067 + process_ce(mci,error_next,celog2_add,celog2_syndrome);
1069 + if(error_one & 0x4040) {
1070 + process_ue_no_info_wr(mci);
1072 + if(error_next & 0x4040) {
1073 + process_ue_no_info_wr(mci);
1075 + if(error_one & 0x2020) {
1076 + process_ded_retry(mci,error_one,retry_add);
1078 + if(error_next & 0x2020) {
1079 + process_ded_retry(mci,error_next,retry_add);
1081 + if(error_one & 0x0808) {
1082 + process_threshold_ce(mci,error_one);
1084 + if(error_next & 0x0808) {
1085 + process_threshold_ce(mci,error_next);
1087 + if(error_one & 0x0606) {
1088 + process_ue(mci,error_one,uelog_add,uelogs_add);
1090 + if(error_next & 0x0606) {
1091 + process_ue(mci,error_next,uelog_add,uelogs_add);
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));
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));
1127 +static int e752x_probe1( struct pci_dev *pdev, int dev_idx )
1131 + u16 pci_data, stat;
1135 + struct mem_ctl_info *mci = NULL;
1136 + struct e752x_pvt *pvt = NULL;
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 */
1143 + unsigned long last_cumul_size;
1144 + struct pci_dev *pres_dev;
1145 + struct pci_dev *dev;
1147 + debugf0( "MC: " __FILE__ ": %s(): mci\n", __func__ );
1148 + printk( KERN_ERR "Starting Probe1\n" );
1150 + /* enable device 0 function 1 */
1151 + pci_read_config_byte(pdev, E752X_DEVPRES1, &stat8);
1153 + pci_write_config_byte(pdev, E752X_DEVPRES1, stat8);
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 */
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;
1165 + mci = bluesmoke_mc_init_structs(sizeof(*pvt),
1171 + goto FAIL_FINISHED;
1174 + debugf3( "MC: " __FILE__ ": %s(): init mci\n", __func__ );
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 $";
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,
1189 + if ( ! pvt->bridge_ck ) {
1190 + pvt->bridge_ck = pci_scan_single_device(pdev->bus, PCI_DEVFN(0,1));
1192 + if ( ! pvt->bridge_ck ) {
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;
1199 + if(ddrcsr & 0x10) {
1200 + pvt->mc_symmetric = 1;
1202 + pvt->mc_symmetric =0;
1205 + debugf3( "MC: " __FILE__ ": %s(): more mci init\n", __func__ );
1206 + mci->ctl_name = pvt->dev_info->ctl_name;
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;
1213 + /* find out the device types */
1214 + pci_read_config_dword(pdev, E752X_DRA, &dra);
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.
1222 + for( last_cumul_size = index = 0; index < mci->nr_csrows; index++ ) {
1225 + /* mem_dev 0=x8, 1=x4 */
1226 + int mem_dev = ( dra >> ( index * 4 + 2 ) ) & 0x3;
1227 + struct csrow_info *csrow = &mci->csrows[ index ];
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 */
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;
1251 + * if single channel or x8 devices then SECDED
1252 + * if dual channel and x4 then S4ECD4ED
1255 + if ( drc_chan && mem_dev ) {
1256 + csrow->edac_mode = EDAC_S4ECD4ED;
1257 + mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
1259 + csrow->edac_mode = EDAC_SECDED;
1260 + mci->edac_cap |= EDAC_FLAG_SECDED;
1263 + csrow->edac_mode = EDAC_NONE;
1267 + /* Fill in the memory map table */
1272 + for(index=0;index<8;index+=2) {
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;
1281 + else { /* there is a dimm in the slot */
1282 + pvt->map[index]=row;
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;
1293 + /* this is a double sided dimm to save the next row # */
1294 + pvt->map[index+1]=row;
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;
1309 + /* map type is reversed */
1310 + pvt->map_type = 0;
1313 + mci->edac_cap |= EDAC_FLAG_NONE;
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);
1326 + if ( 0 != bluesmoke_mc_add_mc( mci ) ) {
1327 + debugf3( "MC: " __FILE__ ": %s(): failed bluesmoke_mc_add_mc()\n", __func__ );
1328 + goto FAIL_FINISHED;
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);
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);
1376 + /* get this far and it's successful */
1377 + debugf3( "MC: " __FILE__ ": %s(): success\n", __func__ );
1392 +static int e752x_suspend (struct pci_dev *pdev, u32 state)
1394 + debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
1400 +static int e752x_resume (struct pci_dev *pdev)
1402 + debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
1407 +#endif /* CONFIG_PM */
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 )
1416 + debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
1418 + /* wake up and enable device */
1419 + if (pci_enable_device (pdev)) {
1422 + rc = e752x_probe1( pdev, ent->driver_data );
1428 +static void __devexit e752x_remove_one( struct pci_dev *pdev )
1430 + struct mem_ctl_info *mci;
1432 + debugf0( __FILE__ ": %s()\n", __func__);
1434 + if ( NULL == ( mci = bluesmoke_mc_find_mci_by_pdev( pdev ) ) ) {
1438 + if ( 0 != bluesmoke_mc_del_mc( mci ) ) {
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. */
1454 +MODULE_DEVICE_TABLE(pci, e752x_pci_tbl);
1457 +static struct pci_driver e752x_driver = {
1459 + probe: e752x_init_one,
1460 + remove: __devexit_p(e752x_remove_one),
1461 + id_table: e752x_pci_tbl,
1463 + suspend: e752x_suspend,
1464 + resume: e752x_resume,
1465 +#endif /* CONFIG_PM */
1469 +int __init e752x_init(void)
1473 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
1474 + pci_rc = pci_module_init( &e752x_driver );
1475 + if ( pci_rc < 0 ) return pci_rc;
1481 +static void __exit e752x_exit(void)
1483 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
1484 + pci_unregister_driver( &e752x_driver );
1488 +module_init(e752x_init);
1489 +module_exit(e752x_exit);
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
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.
1505 + * See "enum e7xxx_chips" below for supported chipsets
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/
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)
1518 + * $Id: bluesmoke_e7xxx.c,v 1.5 2004/11/18 22:19:46 thayne Exp $
1523 +#include <linux/config.h>
1524 +#include <linux/module.h>
1525 +#include <linux/init.h>
1527 +#include <linux/pci.h>
1528 +#include <linux/pci_ids.h>
1530 +#include <linux/slab.h>
1532 +#include "bluesmoke_mc.h"
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
1568 +#define E7XXX_NR_CSROWS 8 /* number of csrows */
1569 +#define E7XXX_NR_DIMMS 8 /* FIXME - is this correct? */
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) */
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
1585 +#define E7XXX_DRC 0x7C /* DRAM controller mode reg (32b) */
1587 + * 22 Number channels 0=1,1=2
1588 + * 19:18 DRB Granularity 32/64MB
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) */
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) */
1601 + * 27:6 CE address (4k block 33:12)
1604 +#define E7XXX_DRAM_UELOG_ADD 0xB0 /* DRAM first uncorrectable memory */
1605 + /* error address register (32b) */
1608 + * 27:6 CE address (4k block 33:12)
1611 +#define E7XXX_DRAM_CELOG_SYNDROME 0xD0 /* DRAM first correctable memory */
1612 + /* error syndrome register (16b) */
1623 + struct pci_dev *bridge_ck;
1627 + const struct e7xxx_dev_info *dev_info;
1631 +struct e7xxx_dev_info {
1633 + const char *ctl_name;
1637 +static const struct e7xxx_dev_info e7xxx_devs[] = {
1639 + .err_dev = PCI_DEVICE_ID_INTEL_7500_1_ERR,
1640 + .ctl_name = "E7500"
1643 + .err_dev = PCI_DEVICE_ID_INTEL_7501_1_ERR,
1644 + .ctl_name = "E7501"
1647 + .err_dev = PCI_DEVICE_ID_INTEL_7505_1_ERR,
1648 + .ctl_name = "E7505"
1651 + .err_dev = PCI_DEVICE_ID_INTEL_7205_1_ERR,
1652 + .ctl_name = "E7205"
1657 +/* FIXME - is this valid for both SECDED and S4ECD4ED? */
1658 +static inline int e7xxx_find_channel(u16 syndrome)
1660 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
1662 + if((syndrome & 0xff00)==0)
1664 + if((syndrome & 0x00ff)==0)
1666 + if((syndrome & 0xf000)==0)
1668 + if((syndrome & 0x0f00)==0)
1674 +static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
1675 + unsigned long page)
1678 + struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info;
1680 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
1682 + if(page < pvt->tolm)
1684 + if((page >= 0x100000)&&(page < pvt->remapbase))
1686 + remap = (page - pvt->tolm) + pvt->remapbase;
1687 + if(remap < pvt->remaplimit)
1689 + printk(KERN_ERR "Invalid page %lx - out of range\n", page);
1690 + return(pvt->tolm-1);
1694 +static void process_ce(struct mem_ctl_info *mci)
1696 + u32 error_1b, page;
1700 + struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info;
1702 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
1704 + /* read the error address */
1705 + pci_read_config_dword(pvt->bridge_ck,E7XXX_DRAM_CELOG_ADD,
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,
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" );
1720 +static void process_ce_no_info(struct mem_ctl_info *mci)
1722 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
1724 + bluesmoke_mc_handle_ce_no_info( mci, "e7xxx CE log register overflow" );
1728 +static void process_ue(struct mem_ctl_info *mci)
1730 + u32 error_2b, block_page;
1732 + struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info;
1734 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
1736 + /* read the error address */
1737 + pci_read_config_dword( pvt->bridge_ck, E7XXX_DRAM_UELOG_ADD,
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" );
1746 +static void process_ue_no_info(struct mem_ctl_info *mci)
1748 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
1750 + bluesmoke_mc_handle_ue_no_info( mci, "e7xxx UE log register overflow" );
1754 +static void e7xxx_check(struct mem_ctl_info *mci)
1756 + u8 error_one, error_next;
1757 + struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info;
1759 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
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);
1764 + /* clear any error bits */
1765 + if(error_one & 3) {
1766 + pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_FERR, 0x03, 0x03);
1768 + if(error_next & 3) {
1769 + pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03, 0x03);
1772 + /* decode and report errors */
1773 + if(error_one & 1) { /* check first error correctable */
1775 + if(error_next & 1) { /* check next error correctable */
1776 + process_ce_no_info(mci);
1778 + if(error_next & 2) { /* check next error uncorrectable */
1781 + } else if(error_one & 2) { /* check first error uncorrectable */
1783 + if(error_next & 1) { /* check next error correctable */
1786 + if(error_next & 2) { /* check next error uncorrectable */
1787 + process_ue_no_info(mci);
1793 +static int e7xxx_probe1( struct pci_dev *pdev, int dev_idx )
1798 + struct mem_ctl_info *mci = NULL;
1799 + struct e7xxx_pvt *pvt = NULL;
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 */
1805 + unsigned long last_cumul_size;
1808 + debugf0( "MC: " __FILE__ ": %s(): mci\n", __func__ );
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;
1816 + mci = bluesmoke_mc_init_structs(sizeof(*pvt),
1822 + goto FAIL_FINISHED;
1825 + debugf3( "MC: " __FILE__ ": %s(): init mci\n", __func__ );
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 $";
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,
1840 + if ( ! pvt->bridge_ck ) {
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;
1848 + debugf3( "MC: " __FILE__ ": %s(): more mci init\n", __func__ );
1849 + mci->ctl_name = pvt->dev_info->ctl_name;
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;
1856 + /* find out the device types */
1857 + pci_read_config_dword(pdev, E7XXX_DRA, &dra);
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.
1865 + for( last_cumul_size = index = 0; index < mci->nr_csrows; index++ ) {
1868 + /* mem_dev 0=x8, 1=x4 */
1869 + int mem_dev = ( dra >> ( index * 4 + 3 ) ) & 0x1;
1870 + struct csrow_info *csrow = &mci->csrows[ index ];
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 */
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;
1890 + * if single channel or x8 devices then SECDED
1891 + * if dual channel and x4 then S4ECD4ED
1894 + if ( drc_chan && mem_dev ) {
1895 + csrow->edac_mode = EDAC_S4ECD4ED;
1896 + mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
1898 + csrow->edac_mode = EDAC_SECDED;
1899 + mci->edac_cap |= EDAC_FLAG_SECDED;
1902 + csrow->edac_mode = EDAC_NONE;
1906 + mci->edac_cap |= EDAC_FLAG_NONE;
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);
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);
1923 + if ( 0 != bluesmoke_mc_add_mc( mci ) ) {
1924 + debugf3( "MC: " __FILE__ ": %s(): failed bluesmoke_mc_add_mc()\n", __func__ );
1925 + goto FAIL_FINISHED;
1928 + /* get this far and it's successful */
1929 + debugf3( "MC: " __FILE__ ": %s(): success\n", __func__ );
1944 +static int e7xxx_suspend (struct pci_dev *pdev, u32 state)
1946 + debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
1952 +static int e7xxx_resume (struct pci_dev *pdev)
1954 + debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
1959 +#endif /* CONFIG_PM */
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 )
1968 + debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
1970 + /* wake up and enable device */
1971 + if (pci_enable_device (pdev)) {
1974 + rc = e7xxx_probe1( pdev, ent->driver_data );
1980 +static void __devexit e7xxx_remove_one( struct pci_dev *pdev )
1982 + struct mem_ctl_info *mci;
1984 + debugf0( __FILE__ ": %s()\n", __func__);
1986 + if ( NULL == ( mci = bluesmoke_mc_find_mci_by_pdev( pdev ) ) ) {
1990 + if ( 0 != bluesmoke_mc_del_mc( mci ) ) {
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. */
2009 +MODULE_DEVICE_TABLE(pci, e7xxx_pci_tbl);
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,
2018 + .suspend = e7xxx_suspend,
2019 + .resume = e7xxx_resume,
2020 +#endif /* CONFIG_PM */
2024 +int __init e7xxx_init(void)
2028 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
2029 + pci_rc = pci_module_init( &e7xxx_driver );
2030 + if ( pci_rc < 0 ) return pci_rc;
2036 +static void __exit e7xxx_exit(void)
2038 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
2039 + pci_unregister_driver( &e7xxx_driver );
2043 +module_init(e7xxx_init);
2044 +module_exit(e7xxx_exit);
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
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.
2062 + * Written by Thayne Harbaugh
2064 + * $Id: bluesmoke_i82875p.c,v 1.5 2004/11/18 22:19:46 thayne Exp $
2069 +#include <linux/config.h>
2070 +#include <linux/module.h>
2071 +#include <linux/init.h>
2073 +#include <linux/pci.h>
2074 +#include <linux/pci_ids.h>
2076 +#include <linux/slab.h>
2078 +#include "bluesmoke_mc.h"
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 */
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 */
2090 +/* four csrows in dual channel, eight in single channel */
2091 +#define I82875P_NR_CSROWS(nr_chans) (8/(nr_chans))
2094 +/* Intel 82875p register addresses - device 0 function 0 - DRAM Controller */
2095 +#define I82875P_EAP 0x58 /* Error Address Pointer (32b)
2097 + * 31:12 block address
2101 +#define I82875P_DERRSYN 0x5c /* DRAM Error Syndrome (8b)
2103 + * 7:0 DRAM ECC Syndrome
2106 +#define I82875P_DES 0x5d /* DRAM Error Status (8b)
2109 + * 0 Error channel 0/1
2112 +#define I82875P_ERRSTS 0xc8 /* Error Status Register (16b)
2115 + * 9 non-DRAM lock error (ndlock)
2116 + * 8 Sftwr Generated SMI
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
2127 +#define I82875P_ERRCMD 0xca /* Error Command (16b)
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
2143 +/* Intel 82875p register addresses - device 6 function 0 - DRAM Controller */
2144 +#define I82875P_PCICMD6 0x04 /* PCI Command Register (16b)
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)
2159 +#define I82875P_BAR6 0x10 /* Mem Delays Base ADDR Reg (32b)
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
2168 +/* Intel 82875p MMIO register space - device 0 function 0 - MMR space */
2170 +#define I82875P_DRB_SHIFT 26 /* 64MiB grain */
2171 +#define I82875P_DRB 0x00 /* DRAM Row Boundary (8b x 8)
2174 + * 6:0 64MiB row boundary addr
2177 +#define I82875P_DRA 0x10 /* DRAM Row Attribute (4b x 8)
2180 + * 6:4 row attr row 1
2182 + * 2:0 row attr row 0
2190 +#define I82875P_DRC 0x68 /* DRAM Controller Mode (32b)
2193 + * 29 init complete
2195 + * 22:21 nr chan 00=1,01=2
2197 + * 19:18 Data Integ Mode 00=none,01=ecc
2199 + * 10:8 refresh mode
2203 + * 1:0 DRAM type 01=DDR
2207 +enum i82875p_chips {
2212 +struct i82875p_pvt {
2213 + struct pci_dev *ovrfl_pdev;
2214 + void *ovrfl_window;
2218 +struct i82875p_dev_info {
2219 + const char *ctl_name;
2223 +static const struct i82875p_dev_info i82875p_devs[] = {
2225 + .ctl_name = "i828875p"
2230 +static void i82875p_check(struct mem_ctl_info *mci)
2234 + u16 errsts, errsts2;
2237 + int multi_chan = mci->csrows[0].nr_channels - 1;
2239 + debugf1( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
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.
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 );
2252 + pci_write_bits16( mci->pdev, I82875P_ERRSTS, 0x0081, 0x0081 );
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.
2260 + if (! (errsts2 & 0x0081) ) return;
2261 + if ( (errsts ^ errsts2) & 0x0081 ) {
2262 + bluesmoke_mc_handle_ce_no_info( mci, "UE overwrote CE" );
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 );
2269 + eap >>= PAGE_SHIFT;
2270 + row = bluesmoke_mc_find_csrow_by_page( mci, eap );
2272 + if ( errsts & 0x0080 ) {
2273 + bluesmoke_mc_handle_ue( mci, eap, 0, row, "i82875p UE" );
2275 + bluesmoke_mc_handle_ce( mci, eap, 0, derrsyn, row,
2276 + multi_chan ? (des & 0x1) : 0,
2284 +static int i82875p_probe1( struct pci_dev *pdev, int dev_idx )
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;
2295 + u32 drc_chan; /* Number of channels 0=1chan,1=2chan */
2297 + u32 drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */
2299 + debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
2301 + ovrfl_pdev = pci_find_device( PCI_VEND_DEV( INTEL, 82875_6 ), NULL );
2303 + if ( ! ovrfl_pdev ) {
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
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;
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",
2322 + goto FAIL_FINISHED;
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",
2329 + goto FAIL_FINISHED;
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",
2335 +#ifdef CORRECT_BIOS
2336 + goto FAIL_FINISHED;
2337 +#endif /* CORRECT_BIOS */
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));
2344 + if (!ovrfl_window) {
2345 + printk( KERN_ERR "MC: " __FILE__
2346 + ": %s(): Failed to ioremap bar6\n",
2348 + goto FAIL_FINISHED;
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;
2357 + mci = bluesmoke_mc_init_structs(sizeof(*pvt),
2358 + I82875P_NR_CSROWS(nr_chans),
2363 + goto FAIL_FINISHED;
2366 + debugf3( "MC: " __FILE__ ": %s(): init mci\n", __func__ );
2369 + mci->mtype_cap = MEM_FLAG_RDDR;
2371 + mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
2372 + mci->edac_cap = EDAC_FLAG_UNKNOWN;
2373 + /* adjust FLAGS */
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;
2382 + debugf3( "MC: " __FILE__ ": %s(): init pvt\n", __func__ );
2384 + pvt = (struct i82875p_pvt *)mci->pvt_info;
2385 + pvt->ovrfl_pdev = ovrfl_pdev;
2386 + pvt->ovrfl_window = ovrfl_window;
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.
2394 + for( last_cumul_size = index = 0; index < mci->nr_csrows; index++ ) {
2397 + struct csrow_info *csrow = &mci->csrows[ index ];
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 */
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;
2417 + /* clear counters */
2418 + pci_write_bits16( mci->pdev, I82875P_ERRSTS, 0x0081, 0x0081 );
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;
2426 + /* get this far and it's successful */
2427 + debugf3( "MC: " __FILE__ ": %s(): success\n", __func__ );
2436 + if (ovrfl_window) {
2437 + iounmap(ovrfl_window);
2441 + pci_release_regions( ovrfl_pdev );
2442 + pci_disable_device( ovrfl_pdev );
2446 + /* NOTE: the ovrfl proc entry and pci_dev are intentionally left */
2453 +static int i82875p_suspend (struct pci_dev *pdev, u32 state)
2455 + debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
2461 +static int i82875p_resume (struct pci_dev *pdev)
2463 + debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
2468 +#endif /* CONFIG_PM */
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 )
2477 + debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
2479 + if (pci_enable_device (pdev)) {
2482 + rc = i82875p_probe1( pdev, ent->driver_data );
2488 +static void __devexit i82875p_remove_one( struct pci_dev *pdev )
2490 + struct mem_ctl_info *mci;
2491 + struct i82875p_pvt *pvt = NULL;
2493 + debugf0( __FILE__ ": %s()\n", __func__);
2495 + if ( NULL == ( mci = bluesmoke_mc_find_mci_by_pdev( pdev ) ) ) {
2499 + pvt = (struct i82875p_pvt *)mci->pvt_info;
2500 + if (pvt->ovrfl_window) {
2501 + iounmap(pvt->ovrfl_window);
2504 + if (pvt->ovrfl_pdev) {
2505 + pci_release_regions( pvt->ovrfl_pdev );
2506 + pci_disable_device( pvt->ovrfl_pdev );
2509 + if ( 0 != bluesmoke_mc_del_mc( mci ) ) {
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. */
2525 +MODULE_DEVICE_TABLE(pci, i82875p_pci_tbl);
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,
2534 + .suspend = i82875p_suspend,
2535 + .resume = i82875p_resume,
2536 +#endif /* CONFIG_PM */
2540 +int __init i82875p_init(void)
2544 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
2545 + pci_rc = pci_module_init( &i82875p_driver );
2546 + if ( pci_rc < 0 ) return pci_rc;
2552 +static void __exit i82875p_exit(void)
2554 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
2555 + pci_unregister_driver( &i82875p_driver );
2559 +module_init(i82875p_init);
2560 +module_exit(i82875p_exit);
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
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.
2577 + * Written by Thayne Harbaugh
2579 + * $Id: bluesmoke_k8.c,v 1.6 2004/11/23 01:34:25 thayne Exp $
2584 +#include <linux/config.h>
2585 +#include <linux/module.h>
2586 +#include <linux/init.h>
2588 +#include <linux/pci.h>
2589 +#include <linux/pci_ids.h>
2591 +#include <linux/slab.h>
2593 +#include "bluesmoke_mc.h"
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 */
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 */
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 */
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 */
2613 +#define K8_NR_CSROWS 8
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)
2620 + * 31:16 DRAM Base addr 39:24
2622 + * 10:8 interleave enable
2627 +#define K8_DLR 0x44 /* DRAM Limit Register (8 x 32b
2628 + * interlaced with K8_DBR)
2630 + * 31:16 DRAM Limit addr 32:24
2632 + * 10:8 interleave select
2634 + * 2:0 destination node ID
2638 +/* K8 register addresses - device 0 function 2 - DRAM controller */
2639 +#define K8_DCSB 0x40 /* DRAM Chip-Select Base (8 x 32b)
2641 + * 31:21 Base addr high 35:25
2643 + * 15:9 Base addr low 19:13 (interlvd)
2645 + * 0 chip-select bank enable
2647 +#define K8_DCSM 0x60 /* DRAM Chip-Select Mask (8 x 32b)
2650 + * 29:21 addr mask high 33:25
2652 + * 15:9 addr mask low 19:13
2656 +#define K8_DBAM 0x80 /* DRAM Base Addr Mapping (32b) */
2657 +#define K8_DCL 0x90 /* DRAM configuration low reg (32b)
2660 + * 27:25 Bypass Max: 000b=respect
2661 + * 24 Dissable receivers - no sockets
2663 + * 19 32byte chunks
2666 + * 16 128/64 bit (dual/single chan)
2667 + * 15:14 R/W Queue bypass count
2669 + * 12 exit self refresh
2670 + * 11 mem clear status
2675 + * 3 dis DQS hysteresis
2677 + * 1 DRAM drive strength
2678 + * 0 Digital Locked Loop disable
2682 +/* K8 register addresses - device 0 function 3 - Misc Control */
2683 +#define K8_NBCTL 0x40 /* MCA NB Control (32b)
2685 + * 1 MCA UE Reporting
2686 + * 0 MCA CE Reporting
2688 +#define K8_NBCFG 0x44 /* MCA NB Config (32b)
2690 + * 23 Chip-kill x4 ECC enable
2692 + * 1 CPU ECC enable
2694 +#define K8_NBSL 0x48 /* MCA NB Status Low (32b)
2696 + * 31:24 Syndrome 15:8 chip-kill x4
2698 + * 19:16 Extended err code
2701 +#define K8_NBSH 0x4C /* MCA NB Status High (32b)
2705 + * 29 Uncorrected err
2707 + * 27 Misc err reg valid
2708 + * 26 Err addr valid
2709 + * 25 proc context corrupt
2711 + * 22:15 Syndrome 7:0
2715 + * 8 err found by scrubber
2717 + * 6:4 Hyper-transport link number
2722 +#define K8_NBEAL 0x50 /* MCA NB err addr low (32b)
2724 + * 31:3 Err addr low 31:3
2727 +#define K8_NBEAH 0x54 /* MCA NB err addr high (32b)
2730 + * 7:0 Err addr high 39:32
2732 +#define K8_NBCAP 0xE8 /* MCA NB capabilities (32b)
2735 + * 4 S4ECD4ED capable
2736 + * 3 SECDED capable
2742 + * K8_MSR_MCxCTL (64b)
2743 + * (0x400,404,408,40C,410)
2744 + * 63 Enable reporting source 63
2748 + * 2 Enable error source 2
2749 + * 1 Enable error source 1
2750 + * 0 Enable error source 0
2753 + * K8_MSR_MCxSTAT (64b)
2754 + * (0x401,405,409,40D,411)
2756 + * 62 Status overflow
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
2767 + * K8_MSR_MCxADDR (64b)
2768 + * (0x402,406,40A,40E,412)
2773 + * K8_MSR_MCxMISC (64b)
2774 + * (0x403,407,40B,40F,413)
2775 + * Unused on Athlon64 and K8
2778 +#define K8_MSR_MCGCTL 0x017b /* Machine Chk Global report ctl (64b)
2784 + * 1 Instruction Cache
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) */
2792 +#define MCI2NID(mci) (PCI_SLOT(mci->pdev->devfn) - 0x18)
2801 + struct pci_dev *addr_map;
2802 + struct pci_dev *misc_ctl;
2806 +struct k8_dev_info {
2807 + const char *ctl_name;
2813 +static const struct k8_dev_info k8_devs[] = {
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
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 )
2828 + *from = pci_find_device( vendor, device, *from );
2829 + if ( ! *from ) return;
2831 + if ( ((*from)->bus->number == related->bus->number)
2832 + && (PCI_SLOT((*from)->devfn)
2833 + == PCI_SLOT(related->devfn)) ) {
2840 +/* FIXME - stolen from msr.c - the calls in msr.c could be exported */
2843 +struct msr_command {
2851 +static void msr_smp_wrmsr(void *cmd_block)
2853 + struct msr_command *cmd = (struct msr_command *) cmd_block;
2855 + debugf1( "MC: " __FILE__ ": %s(): %d ? %d\n",
2856 + __func__, cmd->cpu, smp_processor_id() );
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]);
2866 +static void msr_smp_rdmsr(void *cmd_block)
2868 + struct msr_command *cmd = (struct msr_command *) cmd_block;
2870 + debugf1( "MC: " __FILE__ ": %s(): %d ? %d\n",
2871 + __func__, cmd->cpu, smp_processor_id() );
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]);
2881 +static inline void do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
2883 + struct msr_command cmd;
2885 + debugf0( "MC: " __FILE__ ": %s(): %d\n", __func__, cpu );
2887 + if ( cpu == smp_processor_id() ) {
2888 + wrmsr(reg, eax, edx);
2892 + cmd.data[0] = eax;
2893 + cmd.data[1] = edx;
2895 + smp_call_function(msr_smp_wrmsr, &cmd, 1, 1);
2900 +static inline void do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
2902 + struct msr_command cmd;
2904 + debugf0( "MC: " __FILE__ ": %s(): %d\n", __func__, cpu );
2906 + if ( cpu == smp_processor_id() ) {
2907 + rdmsr(reg, eax, edx);
2912 + smp_call_function(msr_smp_rdmsr, &cmd, 1, 1);
2914 + *eax = cmd.data[0];
2915 + *edx = cmd.data[1];
2919 +#else /* ! CONFIG_SMP */
2921 +static inline void do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
2923 + debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
2924 + wrmsr(reg, eax, edx);
2928 +static inline void do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
2930 + debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
2931 + rdmsr(reg, eax, edx);
2934 +#endif /* ! CONFIG_SMP */
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?
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.
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,
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
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,
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
2998 + * FIXME - either the above table is borken or something is incorrect with
2999 + * the way the syndrome is read out of the NB.
3001 +static int chan_from_syndrome( unsigned long syndrome )
3005 + debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
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;
3012 + debugf0( "MC: " __FILE__ ": %s(): syndrome(%lx) not found\n",
3013 + __func__, syndrome );
3018 +static const char *tt_msgs[] = { /* transaction type */
3026 +static const char *ll_msgs[] = { /* cache level */
3034 +static const char *memtt_msgs[] = {
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"
3054 +static const char *pp_msgs[] = { /* participating processor */
3055 + "local node origin",
3056 + "local node response",
3057 + "local node observed",
3062 +static const char *to_msgs[] = {
3068 +static const char *ii_msgs[] = { /* memory or i/o */
3076 +static const char *ext_msgs[] = { /* extended 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"
3096 +static const char *htlink_msgs[] = {
3108 +static inline void decode_gart_tlb_error( struct mem_ctl_info *mci,
3109 + u32 nbeah, u32 nbeal,
3110 + u32 nbsh, u32 nbsl,
3114 + u32 ec_tt; /* error code transaction type (2b) */
3115 + u32 ec_ll; /* error code cache level (2b) */
3117 + debugf0( "MC%d: " __FILE__ ": %s(): FIXME\n", mci->mc_idx, __func__ );
3119 + err_code = nbsl & 0xffffUL;
3120 + ec_tt = ( err_code >> 2 ) & 0x03UL;
3121 + ec_ll = ( err_code >> 0 ) & 0x03UL;
3123 + printk( "BS%d: GART TLB errorr:"
3124 + " transaction type(%s),"
3125 + " cache level(%s)\n",
3132 +static inline void decode_cache_error( struct mem_ctl_info *mci,
3133 + u32 nbeah, u32 nbeal,
3134 + u32 nbsh, u32 nbsl,
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) */
3142 + debugf0( "MC%d: " __FILE__ ": %s(): FIXME\n", mci->mc_idx, __func__ );
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;
3149 + printk( "BS%d: cache heirarchy error:"
3150 + " memory transaction type(%s),"
3151 + " transaction type(%s),"
3152 + " cache level(%s)\n",
3154 + memtt_msgs[ ec_rrrr ],
3156 + ll_msgs[ ec_ll ] );
3160 +static inline void decode_bus_error( struct mem_ctl_info *mci,
3161 + u32 nbeah, u32 nbeal,
3162 + u32 nbsh, u32 nbsl,
3166 + u32 err_code, ext_ec;
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] = "";
3176 + debugf0( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
3178 + msg_idx = snprintf( msg, 1024, "%s", BS_MOD_STR );
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;
3187 + ext_ec = ( nbsl >> 16 ) & 0xfUL;
3189 + /* FIXME - these should report through bluesmoke channels */
3191 + printk( "BS%d: general bus error:"
3192 + " participating processor(%s),"
3194 + " memory transaction type(%s),"
3195 + " mem or i/o(%s),"
3196 + " cache level(%s)\n",
3200 + memtt_msgs[ ec_rrrr ],
3202 + ll_msgs[ ec_ll ] );
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",
3211 + if ( ec_pp & 0x02 ) {
3212 + /* We aren't the node involved */
3216 + offset = nbeal & ~PAGE_MASK & ~0x7UL;
3217 + page = ( ( nbeah & 0xff ) << ( 40 - PAGE_SHIFT ) )
3218 + | ( ( nbeal & PAGE_MASK ) >> PAGE_SHIFT );
3220 + /* process any errors */
3221 + if ( nbsh & BIT(14) ) { /* CE */
3222 + unsigned long syndrome;
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 );
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
3240 + msg_idx += snprintf( &msg[ msg_idx ], 1024 - msg_idx,
3241 + " unknown syndrome 0x%lx - "
3242 + " possible error reporting race",
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 );
3250 + bluesmoke_mc_handle_ce( mci, page, offset,
3251 + syndrome, row, chan,
3255 + bluesmoke_mc_handle_ce_no_info( mci, msg );
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 );
3263 + bluesmoke_mc_handle_ue( mci, page, offset,
3267 + bluesmoke_mc_handle_ue_no_info( mci, msg );
3271 + if ( nbsh & BIT(30) ) {
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.
3281 + bluesmoke_mc_handle_ce_no_info( mci, BS_MOD_STR );
3286 +static void k8_check(struct mem_ctl_info *mci)
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;
3294 + debugf1( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
3296 + /* check for an error */
3297 + pci_read_config_dword(pvt->misc_ctl, K8_NBSH, &nbsh1);
3298 + if ( ! (nbsh1 & BIT(31) ) ) { /* err valid? */
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 );
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.
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.
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.
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.
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 );
3350 + /* clear the error */
3351 + pci_write_bits32( pvt->misc_ctl, K8_NBSH, 0, BIT(31) );
3353 + if ( ( nbsh1 != nbsh2 )
3354 + || ( nbsl1 != nbsl2 )
3355 + || ( nbeah1 != nbeah2 )
3356 + || ( nbeal1 != nbeal2 ) ) {
3357 + printk( KERN_WARNING "MC%d: race condition detected!\n",
3361 + err_code = nbsl2 & 0xffffUL;
3362 + ext_ec = (nbsl2 >> 16) & 0x0fUL;
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 );
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 );
3381 + printk( "BS%d: extended error code: %s\n",
3383 + ext_msgs[ ext_ec ] );
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 ] );
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?
3398 + if ( nbsh2 & ( BIT(29) | BIT(25) ) ) {
3399 + if ( nbsh2 & BIT(29) )
3400 + printk( "BS%d: uncorrected error\n", mci->mc_idx );
3402 + if ( nbsh2 & BIT(25) )
3403 + printk( "BS%d: processor context corrupt\n",
3406 + panic( "BS%d: cannot recover\n", mci->mc_idx );
3411 +static int k8_probe1( struct pci_dev *pdev, int dev_idx )
3415 + struct mem_ctl_info *mci = NULL;
3416 + struct k8_pvt *pvt = NULL;
3418 + u32 dram_pg_base = 0;
3419 + u32 dram_pg_limit = 0;
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];
3437 + debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
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);
3446 + mci = bluesmoke_mc_init_structs(sizeof(*pvt),
3452 + goto FAIL_FINISHED;
3455 + debugf0( "MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci );
3457 + pvt = (struct k8_pvt *)mci->pvt_info;
3460 + nid = MCI2NID(mci);
3462 + /* setup private structure */
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.
3471 + pci_find_related_function( PCI_VENDOR_ID_AMD,
3476 + if ( ! pvt->addr_map ) {
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;
3485 + debugf1( "Addr Map device PCI Bus ID:\t%s\n", pvt->addr_map->name );
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.
3492 + for ( index = 0; index < 8; index++ ) {
3499 + u32 dlr_limit = 0;
3503 + pci_read_config_dword( pvt->addr_map,
3504 + K8_DLR + (8 * index),
3507 + dlr_nid = dlr & 0x7;
3509 + if ( dlr_nid != nid ) continue;
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.
3516 + dlr_limit = ((((dlr >> 16) & 0xffff) + 1)
3517 + << (24 - PAGE_SHIFT)) - 1;
3518 + dlr_intsel = (dlr >> 8) & 0x1f;
3520 + pci_read_config_dword( pvt->addr_map,
3521 + K8_DBR + (8 * index),
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;
3529 + debugf1( "\tAddr Map: %d:0x%x - 0x%x\n",
3530 + dlr_nid, dbr_base, dlr_limit );
3532 + if ( dram_pg_limit ) {
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;
3541 + dram_pg_limit = dlr_limit;
3542 + dram_pg_base = dbr_base;
3545 + if (! dram_pg_limit) {
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;
3553 + pci_find_related_function( PCI_VENDOR_ID_AMD,
3558 + if ( ! pvt->misc_ctl ) {
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;
3567 + debugf1( "Misc device PCI Bus ID:\t\t%.2x:%.2x.%.1x\n",
3568 + pvt->misc_ctl->name );
3570 + pci_read_config_dword( pvt->misc_ctl, K8_NBCFG, &nbcfg );
3571 + nbcfg_ckx4en = nbcfg & BIT(23);
3572 + nbcfg_eccen = nbcfg & BIT(22);
3574 + mci->mtype_cap = MEM_FLAG_DDR | MEM_FLAG_RDDR;
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;
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;
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;
3598 + for ( index = 0; index < mci->nr_csrows; index++ ) {
3599 + struct csrow_info *csrow = &mci->csrows[ index ];
3607 + u32 device_shift = 0;
3608 + u32 intlv_shift = 0;
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 */
3617 + dcsb_bal = ((dcsb >> 9) & 0x7fUL) << (13 - PAGE_SHIFT);
3618 + dcsb_bah = ((dcsb >> 21) & 0x7ffUL) << (25 - PAGE_SHIFT);
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);
3624 + debugf2( "\t%d: dcsb(%x) dcsm(%x)\n", index, dcsb, dcsm );
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);
3633 + while ( ! (aml & 0x1UL) ) {
3640 + while ( aml & 0x1UL ) {
3646 + csrow->last_page = csrow->first_page
3647 + + ( csrow->nr_pages << intlv_shift )
3648 + - ( (1 << device_shift) | 0x1UL );
3650 + csrow->last_page = csrow->first_page
3651 + + csrow->nr_pages - 1;
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;
3660 + csrow->dtype = DEV_UNKNOWN;
3663 + if ( nbcfg_eccen ) {
3664 + if ( nbcfg_ckx4en ) {
3665 + csrow->edac_mode = EDAC_S4ECD4ED;
3667 + csrow->edac_mode = EDAC_SECDED;
3670 + csrow->edac_mode = EDAC_NONE;
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) );
3678 + if ( ! csrows_loaded ) {
3679 + mci->edac_cap = EDAC_FLAG_NONE;
3681 + /* turn on error reporting */
3682 + pci_write_bits32( pvt->misc_ctl, K8_NBCTL, 0x3UL, 0x3UL );
3684 + pci_write_bits32( pvt->misc_ctl, K8_NBCTL, 0x3UL, 0x3UL );
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 );
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 );
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;
3703 + /* get this far and it's successful */
3704 + debugf3( "MC: " __FILE__ ": %s(): success\n", __func__ );
3720 +static int k8_suspend (struct pci_dev *pdev, u32 state)
3722 + debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
3728 +static int k8_resume (struct pci_dev *pdev)
3730 + debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
3735 +#endif /* CONFIG_PM */
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 )
3744 + debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
3746 + /* wake up and enable device */
3747 + if (pci_enable_device (pdev)) {
3750 + rc = k8_probe1( pdev, ent->driver_data );
3756 +static void __devexit k8_remove_one( struct pci_dev *pdev )
3758 + struct mem_ctl_info *mci;
3760 + debugf0( __FILE__ ": %s()\n", __func__);
3762 + if ( NULL == ( mci = bluesmoke_mc_find_mci_by_pdev( pdev ) ) ) {
3766 + if ( 0 != bluesmoke_mc_del_mc( mci ) ) {
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. */
3782 +MODULE_DEVICE_TABLE(pci, k8_pci_tbl);
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,
3791 + .suspend = k8_suspend,
3792 + .resume = k8_resume,
3793 +#endif /* CONFIG_PM */
3797 +int __init k8_init(void)
3801 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
3802 + pci_rc = pci_module_init( &k8_driver );
3803 + if ( pci_rc < 0 ) return pci_rc;
3809 +static void __exit k8_exit(void)
3811 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
3812 + pci_unregister_driver( &k8_driver );
3816 +module_init(k8_init);
3817 +module_exit(k8_exit);
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
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.
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/
3838 + * $Id: bluesmoke_mc.c,v 1.9 2004/12/13 22:19:40 thayne Exp $
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>
3854 +#include <asm/uaccess.h>
3855 +#include <asm/page.h>
3857 +#include "bluesmoke_mc.h"
3860 +#ifndef pfn_to_page
3861 +#define pfn_to_page(pfn) (mem_map + (pfn))
3862 +#endif /* pfn_to_page */
3864 +#define MC_PROC_DIR "mc"
3867 +static struct proc_dir_entry *proc_mc;
3869 +/* Setable by module parameter and sysctl */
3871 +/* FIXME - do something with scrubbing */
3872 +static int mc_scrub = -1;
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;
3880 +static DECLARE_MUTEX(mem_ctls_mutex);
3882 +/* FIXME - use list.h */
3883 +/* FIXME - should be dynamic */
3884 +static struct mem_ctl_info *mcis[MAX_MC_DEVICES];
3887 +#ifdef CONFIG_SYSCTL
3888 +static void dimm_labels( char *buf, void *data )
3890 + int mcidx, ridx, chidx;
3891 + char *mcstr, *rstr, *chstr, *lstr, *p;
3895 + mcstr = strsep( &lstr, "." );
3898 + mcidx = simple_strtol( mcstr, &p, 0 );
3901 + if ( mcidx >= MAX_MC_DEVICES || ! mcis[mcidx] )
3904 + rstr = strsep( &lstr, "." );
3907 + ridx = simple_strtol( rstr, &p, 0 );
3910 + if ( ridx >= mcis[mcidx]->nr_csrows
3911 + || ! mcis[mcidx]->csrows )
3914 + chstr = strsep( &lstr, ":" );
3917 + chidx = simple_strtol( chstr, &p, 0 );
3920 + if ( chidx >= mcis[mcidx]->csrows[ridx].nr_channels
3921 + || ! mcis[mcidx]->csrows[ridx].channels )
3924 + debugf1( "%d:%d.%d:%s\n",
3925 + mcidx, ridx, chidx, lstr );
3927 + strncpy(mcis[mcidx]->csrows[ridx].channels[chidx].label,
3928 + lstr, BLUESMOKE_MC_LABEL_LEN + 1);
3930 + * no need to NUL terminate label since
3931 + * get_user_tok() NUL terminates.
3936 +static void counter_reset( char *buf, void *data )
3939 + int mcidx, row, chan;
3940 + struct mem_ctl_info *mci;
3942 + mcidx = simple_strtol( buf, &p, 0 );
3945 + if ( mcidx >= MAX_MC_DEVICES || ! mcis[mcidx] )
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];
3958 + for ( chan = 0; chan < ri->nr_channels; chan++ ) {
3959 + ri->channels[chan].ce_count = 0;
3962 + do_gettimeofday( &mci->tv );
3966 +struct actionvec_info {
3967 + void (*action)(char *str, void *data);
3974 +static struct actionvec_info dimm_labels_avi = {
3975 + .action = dimm_labels,
3977 + .usage = "<mc>.<row>.<chan>:<label>"
3978 + "[,<mc>.<row>.<chan>:<label>[,...]]\n",
3983 +static struct actionvec_info counter_reset_avi = {
3984 + .action = counter_reset,
3986 + .usage = "<mc>[,<mc>[,...]]\n",
3991 +static int proc_actionvec( ctl_table *table, int write, struct file *filp,
3992 + void *buffer, size_t *lenp )
3995 + char *p, c, *buf, *tok, sep[] = " ";
3996 + struct actionvec_info *avi;
3998 + debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
4000 + if ( !table->data || !*lenp || (filp->f_pos && !write)) {
4005 + avi = (struct actionvec_info *)table->data;
4008 + /* dup the string from user space */
4011 + while (len < *lenp) {
4012 + if (get_user(c, p++))
4014 + if (c == 0 || c == '\n')
4018 + if (! (buf = kmalloc(len + 1, GFP_KERNEL)))
4020 + if (copy_from_user(buf, buffer, len)) {
4025 + filp->f_pos += *lenp;
4026 + /* working copy can now be segmented for processing */
4028 + sep[0] = avi->separator;
4029 + while ((tok = strsep(&p, sep)))
4030 + avi->action(tok, avi->data);
4033 + len = strlen(avi->usage);
4037 + if(copy_to_user(buffer, avi->usage, len))
4040 + filp->f_pos += len;
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},
4063 +static ctl_table mc_root_table[] = {
4064 + {CTL_DEBUG, MC_PROC_DIR, NULL, 0, 0555, mc_table},
4069 +static struct ctl_table_header *mc_sysctl_header = NULL;
4070 +#endif /* CONFIG_SYSCTL */
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"
4088 +static const char *dev_types[] = {
4089 + [DEV_UNKNOWN] = "Unknown",
4094 + [DEV_X16] = "x16",
4095 + [DEV_X32] = "x32",
4099 +static const char *edac_caps[] = {
4100 + [EDAC_UNKNOWN] = "Unknown",
4101 + [EDAC_NONE] = "None",
4102 + [EDAC_RESERVED] = "Reserved",
4103 + [EDAC_PARITY] = "PARITY",
4105 + [EDAC_SECDED] = "SECDED",
4106 + [EDAC_S2ECD2ED] = "S2ECD2ED",
4107 + [EDAC_S4ECD4ED] = "S4ECD4ED",
4108 + [EDAC_S8ECD8ED] = "S8ECD8ED",
4109 + [EDAC_S16ECD16ED] = "S16ECD16ED"
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"
4126 +#endif /* UNUSED */
4129 +/* FIXME - CHANNEL_PREFIX is pretty bad */
4130 +#define CHANNEL_PREFIX(...) \
4132 + p += sprintf( p, "%d.%d:%s", \
4133 + chan->csrow->csrow_idx, \
4136 + p += sprintf( p, ":" __VA_ARGS__ ); \
4140 +static inline int mc_proc_output_channel(char *buf, struct channel_info *chan)
4144 + CHANNEL_PREFIX( "CE:\t\t%d\n", chan->ce_count );
4149 +#undef CHANNEL_PREFIX
4152 +#define CSROW_PREFIX(...) \
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 ); \
4160 + p += sprintf( p, ":" __VA_ARGS__ ); \
4164 +static inline int mc_proc_output_csrow(char *buf, struct csrow_info *csrow)
4169 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
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 );
4179 + for ( chan_idx = 0; chan_idx < csrow->nr_channels; chan_idx++ ) {
4180 + p += mc_proc_output_channel( p, &csrow->channels[chan_idx] );
4182 + p += sprintf( p, "\n" );
4186 +#undef CSROW_PREFIX
4189 +static inline int mc_proc_output_edac_cap(char *buf, unsigned long edac_cap)
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 ] );
4204 +static inline int mc_proc_output_mtype_cap(char *buf, unsigned long mtype_cap)
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 ] );
4219 +static int mc_proc_output(struct mem_ctl_info *mci, char *buf)
4224 + struct timeval tv;
4226 + debugf3( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
4228 + do_gettimeofday( &tv );
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 );
4235 + p += sprintf( p, "\n" );
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) );
4242 + p += sprintf( p, "EDAC capability:\t" );
4243 + p += mc_proc_output_edac_cap( p, mci->edac_ctl_cap );
4244 + p += sprintf( p, "\n" );
4246 + p += sprintf( p, "Current EDAC capability:\t" );
4247 + p += mc_proc_output_edac_cap( p, mci->edac_cap );
4248 + p += sprintf( p, "\n" );
4250 + p += sprintf( p, "Supported Mem Types:\t" );
4251 + p += mc_proc_output_mtype_cap( p, mci->mtype_cap );
4252 + p += sprintf( p, "\n" );
4254 + p += sprintf( p, "\n" );
4256 + for ( total_pages = csrow_idx = 0;
4257 + csrow_idx < mci->nr_csrows;
4259 + struct csrow_info *csrow = &mci->csrows[csrow_idx];
4261 + if ( ! csrow->nr_pages ) continue;
4262 + total_pages += csrow->nr_pages;
4263 + p += mc_proc_output_csrow( p, csrow );
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 );
4278 +static int mc_read_proc(char *page, char **start, off_t off,
4279 + int count, int *eof, void *data)
4282 + struct mem_ctl_info *mci = (struct mem_ctl_info *)data;
4284 + debugf3( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
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;
4292 + if (len>count) len = count;
4293 + if (len<0) len = 0;
4298 +#endif /* CONFIG_PROC_FS */
4301 +#if CONFIG_BLUESMOKE_DEBUG
4304 +EXPORT_SYMBOL(bluesmoke_mc_dump_channel);
4306 +void bluesmoke_mc_dump_channel( struct channel_info *chan )
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 );
4316 +EXPORT_SYMBOL(bluesmoke_mc_dump_csrow);
4318 +void bluesmoke_mc_dump_csrow( struct csrow_info *csrow )
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 );
4332 +EXPORT_SYMBOL(bluesmoke_mc_dump_mci);
4334 +void bluesmoke_mc_dump_mci( struct mem_ctl_info *mci )
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 );
4353 +#endif /* CONFIG_BLUESMOKE_DEBUG */
4356 +EXPORT_SYMBOL(bluesmoke_mc_init_structs);
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.
4363 + * kmalloc'ed memory must be free'ed by caller.
4365 +struct mem_ctl_info *bluesmoke_mc_init_structs(u32 sz_pvt,
4369 + struct mem_ctl_info *mci;
4370 + struct channel_info *chi;
4375 + sizeof(struct mem_ctl_info)
4377 + + nr_csrows * sizeof(struct csrow_info)
4378 + + nr_chans * nr_csrows * sizeof(struct channel_info);
4380 + if (! (mci = kmalloc(malloc_size, GFP_KERNEL)))
4383 + memset( mci, 0, malloc_size);
4385 + /* set all the pointers to the correct offset in the malloc'ed block */
4387 + mci->pvt_info = (pvt_info_t)((char *)mci + sizeof(*mci));
4389 + mci->csrows = (struct csrow_info *)((char *)mci + sizeof(*mci) + sz_pvt);
4390 + mci->nr_csrows = nr_csrows;
4392 + chi = (struct channel_info *)((char *)mci->csrows
4393 + + sizeof(*mci->csrows) * nr_csrows);
4395 + for (row = 0; row < nr_csrows; row++) {
4396 + struct csrow_info *csrow = &mci->csrows[row];
4398 + csrow->csrow_idx = row;
4400 + csrow->nr_channels = nr_chans;
4401 + csrow->channels = &chi[ row * nr_chans ];
4403 + for (chn = 0; chn < nr_chans; chn++) {
4404 + struct channel_info *chan = &csrow->channels[ chn ];
4406 + chan->chan_idx = chn;
4407 + chan->csrow = csrow;
4416 +EXPORT_SYMBOL(bluesmoke_mc_find_mci_by_pdev);
4418 +struct mem_ctl_info *bluesmoke_mc_find_mci_by_pdev(struct pci_dev *pdev )
4421 + struct mem_ctl_info *mci = NULL;
4423 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
4425 + for (i=0; i < MAX_MC_DEVICES; i++) {
4426 + if ( ! mcis[ i ] ) continue;
4427 + if ( pdev == mcis[ i ]->pdev ) {
4437 +EXPORT_SYMBOL(bluesmoke_mc_add_mc);
4439 +/* FIXME - should a warning be printed if no error detection? correction? */
4440 +int bluesmoke_mc_add_mc(struct mem_ctl_info *mci)
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++ ) {
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] );
4458 +#endif /* 2 <= CONFIG_BLUESMOKE_DEBUG_VERBOSE */
4459 +#endif /* CONFIG_BLUESMOKE_DEBUG */
4460 + down( &mem_ctls_mutex );
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),
4472 + for (i=0; i < MAX_MC_DEVICES; i++) {
4473 + if ( ! mcis[ i ] ) break;
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);
4486 + "MC%d: Giving out device %d to %s %s: PCI %s (%s)\n",
4488 + i, mci->mod_name, mci->ctl_name,
4489 + mci->pdev->slot_name, pci_name(mci->pdev) );
4490 + __module_get(THIS_MODULE);
4492 + /* set load time so that error rate can be tracked */
4493 + do_gettimeofday(&mci->tv);
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",
4501 + /* FIXME - should there be an error code and unwind? */
4505 + mci->proc_ent = create_proc_read_entry( mci->proc_name, 0, proc_mc,
4506 + mc_read_proc, (void *)mci );
4508 + if ( NULL == mci->proc_ent ) {
4509 + printk( KERN_WARNING
4510 + "MC%d: failed to create proc entry for controller %d \n",
4512 + /* FIXME - should there be an error code and unwind? */
4515 +#endif /* CONFIG_PROC_FS */
4520 + up( &mem_ctls_mutex );
4525 +EXPORT_SYMBOL(bluesmoke_mc_del_mc);
4527 +int bluesmoke_mc_del_mc(struct mem_ctl_info *mci)
4531 + debugf0( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
4532 + down( &mem_ctls_mutex );
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);
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 );
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) );
4558 + up( &mem_ctls_mutex );
4564 + * FIXME - what happens when grain > PAGE_SIZE?
4565 + * Need multiple kmap_atomic()
4567 +/* FIXME - this should go in an arch dependant file */
4568 +EXPORT_SYMBOL(bluesmoke_mc_scrub_block);
4570 +void bluesmoke_mc_scrub_block(unsigned long page, unsigned long offset, u32 size)
4573 + volatile unsigned long *virt_addr;
4576 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
4577 +#ifndef CONFIG_DISCONTIGMEM
4578 + if(page > max_mapnr)
4579 + return; /* pointer is beyond memory, so bail */
4581 +/* FIXME - use the per-pgdat data instead for discontigmem */
4583 + pg = pfn_to_page(page);
4585 + virt_addr = kmap_atomic(pg, KM_BOUNCE_READ) + offset;
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.
4591 + __asm__ __volatile__(
4592 + "lock; addl $0, %0"
4593 + :: "m" (*virt_addr));
4595 + kunmap_atomic(pg, KM_BOUNCE_READ);
4599 +/* FIXME - put in a util library? */
4600 +/* FIXME - should return -1 */
4601 +EXPORT_SYMBOL(bluesmoke_mc_find_csrow_by_page);
4603 +int bluesmoke_mc_find_csrow_by_page( struct mem_ctl_info *mci,
4604 + unsigned long page )
4606 + struct csrow_info *csrows = mci->csrows;
4609 + debugf1( "MC%d: " __FILE__ ": %s(): 0x%lx\n",
4610 + mci->mc_idx, __func__, page );
4612 + for ( i = 0; i < mci->nr_csrows; i++ ) {
4613 + struct csrow_info *csrow = &csrows[i];
4615 + if ( 0 == csrow->nr_pages ) continue;
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,
4624 + csrow->page_mask );
4626 + if ( ( page >= csrow->first_page )
4627 + && ( page <= csrow->last_page )
4628 + && ((page & csrow->page_mask)
4629 + == (csrow->first_page & csrow->page_mask)) ) {
4637 + "MC%d: could not look up page error address %lx\n",
4638 + mci->mc_idx, (unsigned long)page);
4645 +EXPORT_SYMBOL(bluesmoke_mc_handle_ce);
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,
4657 + unsigned long remapped_page;
4659 + debugf3( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
4661 + /* FIXME - maybe make panic on INTERNAL ERROR an option */
4662 + if ( row >= mci->nr_csrows || row < 0 ) {
4663 + /* something is wrong */
4665 + "MC%d: INTERNAL ERROR: row out of range (%d >= %d)\n",
4667 + row, mci->nr_csrows );
4668 + bluesmoke_mc_handle_ce_no_info( mci, "INTERNAL ERROR" );
4671 + if ( channel >= mci->csrows[row].nr_channels || channel < 0 ) {
4672 + /* something is wrong */
4674 + "MC%d: INTERNAL ERROR: channel out of range (%d >= %d)\n",
4676 + channel, mci->csrows[row].nr_channels );
4677 + bluesmoke_mc_handle_ce_no_info( mci, "INTERNAL ERROR" );
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",
4688 + page_frame_number,
4690 + mci->csrows[row].grain,
4694 + mci->csrows[row].channels[channel].label,
4699 + mci->csrows[row].ce_count++;
4700 + mci->csrows[row].channels[channel].ce_count++;
4702 + if ( mci->scrub_mode & SCRUB_SW_SRC ) {
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.
4712 + if ( mci->ctl_page_to_phys ) {
4713 + remapped_page = mci->ctl_page_to_phys(mci,
4714 + page_frame_number);
4716 + remapped_page = page_frame_number;
4718 + bluesmoke_mc_scrub_block(remapped_page,
4720 + mci->csrows[row].grain);
4725 +EXPORT_SYMBOL(bluesmoke_mc_handle_ce_no_info);
4727 +void bluesmoke_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg)
4730 + printk( KERN_WARNING
4731 + "MC%d: CE - no information available: %s\n",
4732 + mci->mc_idx, msg );
4734 + mci->ce_noinfo_count++;
4739 +EXPORT_SYMBOL(bluesmoke_mc_handle_ue);
4741 +void bluesmoke_mc_handle_ue(struct mem_ctl_info *mci,
4742 + unsigned long page_frame_number,
4743 + unsigned long offset_in_page,
4747 + int len = BLUESMOKE_MC_LABEL_LEN * 4;
4748 + char labels[len + 1];
4749 + char *pos = labels;
4753 + debugf3( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
4755 + /* FIXME - maybe make panic on INTERNAL ERROR an option */
4756 + if ( row >= mci->nr_csrows || row < 0 ) {
4757 + /* something is wrong */
4759 + "MC%d: INTERNAL ERROR: row out of range (%d >= %d)\n",
4761 + row, mci->nr_csrows );
4762 + bluesmoke_mc_handle_ue_no_info( mci, "INTERNAL ERROR" );
4766 + chars = snprintf( pos, len + 1, "%s",
4767 + mci->csrows[row].channels[0].label );
4771 + (chan < mci->csrows[row].nr_channels) && (len > 0);
4773 + chars = snprintf( pos, len + 1, ":%s",
4774 + mci->csrows[row].channels[chan].label );
4780 + printk( KERN_EMERG
4781 + "MC%d: UE page 0x%lx, offset 0x%lx, grain %d, row %d,"
4782 + " labels \"%s\": %s\n",
4784 + page_frame_number,
4786 + mci->csrows[row].grain,
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",
4796 + page_frame_number,
4798 + mci->csrows[row].grain,
4805 + mci->csrows[row].ue_count++;
4809 +EXPORT_SYMBOL(bluesmoke_mc_handle_ue_no_info);
4811 +void bluesmoke_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg)
4813 + if (panic_on_ue) panic("MC%d: Uncorrected Error", mci->mc_idx);
4816 + printk( KERN_WARNING
4817 + "MC%d: UE - no information available: %s\n",
4818 + mci->mc_idx, msg );
4820 + mci->ue_noinfo_count++;
4826 + * Check MC status every poll_msec.
4827 + * SMP safe, doesn't use NMI, and auto-rate-limits.
4829 +static void check_mc(unsigned long dummy)
4833 + debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
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);
4840 + timer.function = check_mc;
4841 + timer.expires = jiffies + (HZ * poll_msec) / 1000;
4842 + add_timer(&timer);
4847 + down(&mem_ctls_mutex);
4849 + for ( i = 0; i < MAX_MC_DEVICES; i++ ) {
4850 + struct mem_ctl_info *mci = mcis[ i ];
4852 + if ( NULL == mci ) continue;
4854 + /* FIXME - should check scrub flag */
4855 + if ( ! mci->scrub_needed
4856 + && mci->edac_check ) {
4857 + mci->edac_check(mci);
4860 + if ( mci->clear_err ) mci->clear_err(mci);
4863 + if (timer_pending(&timer)) {
4864 + mod_timer(&timer, jiffies + (HZ * poll_msec) / 1000);
4866 + timer.function = check_mc;
4867 + timer.expires = jiffies + (HZ * poll_msec) /1000;
4868 + add_timer(&timer);
4871 + up( &mem_ctls_mutex );
4875 +int __init bluesmoke_mc_init(void)
4879 + debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
4880 + printk( KERN_INFO "MC: " __FILE__ " version " BLUESMOKE_MC_VER "\n" );
4882 + memset( mcis, 0, sizeof(mcis) );
4886 +#ifdef CONFIG_PROC_FS
4887 + if ( NULL == (proc_mc = proc_mkdir( MC_PROC_DIR, &proc_root ) ) ) {
4890 +#endif /* CONFIG_PROC_FS */
4892 +#ifdef CONFIG_SYSCTL
4893 + mc_sysctl_header = register_sysctl_table(mc_root_table, 1);
4894 +#endif /* CONFIG_SYSCTL */
4903 +static void __exit bluesmoke_mc_exit(void)
4905 + debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
4907 +#ifdef CONFIG_PROC_FS
4908 + if ( proc_mc ) remove_proc_entry( MC_PROC_DIR, &proc_root );
4909 +#endif /* CONFIG_PROC_FS */
4911 +#ifdef CONFIG_SYSCTL
4912 + if (mc_sysctl_header) {
4913 + unregister_sysctl_table(mc_sysctl_header);
4914 + mc_sysctl_header = NULL;
4916 +#endif /* CONFIG_SYSCTL */
4920 +module_init(bluesmoke_mc_init);
4921 +module_exit(bluesmoke_mc_exit);
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");
4929 +MODULE_PARM(mc_scrub, "i");
4930 +MODULE_PARM_DESC(mc_scrub, "Force MC scrubbing: 0=off 1=on");
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
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.
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/
4955 + * $Id: bluesmoke_mc.h,v 1.4 2004/11/10 01:12:36 thayne Exp $
4960 +#ifndef _BLUESMOKE_MC_H_
4961 +#define _BLUESMOKE_MC_H_
4964 +#include <linux/pci.h>
4965 +#include <linux/time.h>
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
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 ) )
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__ )
4984 +#define debugf0( ... )
4987 +#if 1 <= CONFIG_BLUESMOKE_DEBUG_VERBOSE
4988 +#define debugf1( ... ) printk( __VA_ARGS__ )
4990 +#define debugf1( ... )
4993 +#if 2 <= CONFIG_BLUESMOKE_DEBUG_VERBOSE
4994 +#define debugf2( ... ) printk( __VA_ARGS__ )
4996 +#define debugf2( ... )
4999 +#if 3 <= CONFIG_BLUESMOKE_DEBUG_VERBOSE
5000 +#define debugf3( ... ) printk( __VA_ARGS__ )
5002 +#define debugf3( ... )
5005 +#else /* !CONFIG_BLUESMOKE_DEBUG || !CONFIG_BLUESMOKE_DEBUG_VERBOSE */
5007 +#define debugf0( ... )
5008 +#define debugf1( ... )
5009 +#define debugf2( ... )
5010 +#define debugf3( ... )
5011 +#endif /* !CONFIG_BLUESMOKE_DEBUG || !CONFIG_BLUESMOKE_DEBUG_VERBOSE */
5014 +#define bs_xstr(s) bs_str(s)
5015 +#define bs_str(s) #s
5016 +#define BS_MOD_STR bs_xstr(KBUILD_BASENAME)
5018 +#define BIT(x) (1 << (x))
5020 +#define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, PCI_DEVICE_ID_ ## vend ## _ ## dev
5022 +/* memory devices */
5030 + DEV_X32, /* Do these parts exist? */
5031 + DEV_X64 /* Do these parts exist? */
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)
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 */
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)
5071 +/* chipset Error Detection and Correction capabilities and mode */
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 */
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)
5096 +/* scrubbing capabilities */
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 */
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)
5120 +/* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */
5124 + * There are several things to be aware of that aren't at all obvious:
5127 + * SOCKETS, SOCKET SETS, BANKS, ROWS, CHIP-SELECT ROWS, CHANNELS, etc..
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.
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.
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.
5144 + * Socket: A physical connector on the motherboard that accepts
5145 + * a single memory stick.
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").
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
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.
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
5177 + * Bank: This term is avoided because it is unclear when
5178 + * needing to distinguish between chip-select rows and
5182 + * Controller pages:
5189 + * STRUCTURE ORGANIZATION AND CHOICES
5193 + * PS - I enjoyed writing all that about as much as you enjoyed reading it.
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 */
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 */
5220 + struct channel_info *channels;
5224 +typedef void *pvt_info_t;
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);
5244 + * Remaps memory pages: controller pages to physical pages.
5245 + * For most MC's, this will be NULL.
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);
5252 + struct csrow_info *csrows;
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.
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;
5266 + pvt_info_t pvt_info;
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 */
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 )
5280 + if ( mask != 0xff ){
5282 + pci_read_config_byte( pdev, offset, &buf);
5287 + pci_write_config_byte( pdev, offset, value );
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 )
5295 + if ( mask != 0xffff ){
5297 + pci_read_config_word( pdev, offset, &buf );
5302 + pci_write_config_word( pdev, offset, value);
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 )
5310 + if ( mask != 0xffff ){
5312 + pci_read_config_dword( pdev, offset, &buf );
5317 + pci_write_config_dword( pdev, offset, value );
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 */
5327 +extern int bluesmoke_mc_add_mc(struct mem_ctl_info *mci);
5328 +extern int bluesmoke_mc_del_mc(struct mem_ctl_info *mci);
5330 +extern int bluesmoke_mc_find_csrow_by_page( struct mem_ctl_info *mci,
5331 + unsigned long page );
5333 +extern struct mem_ctl_info *bluesmoke_mc_find_mci_by_pdev(struct pci_dev *pdev );
5335 +extern void bluesmoke_mc_scrub_block(unsigned long page,
5336 + unsigned long offset,
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.
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,
5357 +extern void bluesmoke_mc_handle_ce_no_info(struct mem_ctl_info *mci,
5360 +extern void bluesmoke_mc_handle_ue(struct mem_ctl_info *mci,
5361 + unsigned long page_frame_number,
5362 + unsigned long offset_in_page,
5366 +extern void bluesmoke_mc_handle_ue_no_info(struct mem_ctl_info *mci,
5370 + * This kmalloc's and initializes all the structures.
5371 + * Can't be used if all structures don't have the same lifetime.
5373 +extern struct mem_ctl_info *bluesmoke_mc_init_structs(u32 sz_pvt,
5377 +#include "compatmac.h"
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
5385 +#ifndef __LINUX_BLUESMOKE_COMPATMAC_H__
5386 +#define __LINUX_BLUESMOKE_COMPATMAC_H__
5388 +#include <linux/version.h>
5389 +#include <linux/pci.h>
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!
5395 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
5397 +#define pci_name(pci_dev) ((pci_dev)->slot_name)
5399 +#ifndef pci_pretty_name
5400 +# define pci_pretty_name(pdev) ""
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)
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.
5419 +static inline struct pci_dev *pci_scan_single_device( struct pci_bus *bus,
5422 + struct pci_dev tmp_pdev, *pdev = NULL;
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 );
5436 +#ifndef pci_pretty_name
5437 +# define pci_pretty_name(pdev) ((pdev)->pretty_name)
5440 +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) */
5443 +#define in_atomic() 0
5444 +#define down_trylock(mtx) 1
5445 +#endif /* in_atomic */
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
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