2009-03-11 03:39:09

by Harry Ciao

[permalink] [raw]
Subject: [v2 PATCH 0/7] Add AMD8111 and AMD8131 EDAC drivers


Hi,

This is the v2 series of patches for EDAC AMD8111 & AMD8131 drivers.
I have integrated suggestions from Bert, Greg and Andrew.
Tests all passed on Maple platform, these modules could be properly
loaded/unloaded, with their sysfs interfaces created/cleaned.

Any suggestions are warmly welcomed!

Best regards,

Harry


Comments:
---------
Introduce AMD8111 EDAC driver, which makes use of error detections
on the LPC Bridge Controller and PCI Bridge Controller on the AMD8111
HyperTransport I/O Hub.

Introduce AMD8131 EDAC driver source file, which makes use of error
detections on the PCI-X Bridge Controllers on the AMD8131 HyperTransport
PCI-X Tunnel.

Since both AMD8111 and AMD8131 EDAC drivers would use edac_pci_ctl_info
structures, EDAC core has to take the responsibility to allocate a unique
"edac_pci_idx" for each of them, by newly added edac_pci_alloc_index().

Note, by far only POLL mode is supported, and they have been tested on
MAPLE platform, from below test logs we can tell that they could be
correctly installed and removed, and export proper sysfs interfaces.

Test steps:
-----------
CONFIG_EDAC=y
CONFIG_EDAC_DEBUG=y
CONFIG_EDAC_MM_EDAC=m
CONFIG_EDAC_AMD8111=m
CONFIG_EDAC_AMD8131=m

insmod edac_core.ko
dmesg -n 8
insmod amd8111_edac.ko
cd /sys/devices/system/edac
ls -lt
ls -lt pci/ ,etc
ls -lt lpc/ ,etc
rmmod amd8111_edac
insmod amd8131_edac.ko
insmod amd8111_edac.ko
cd /sys/devices/system/edac
ls -lt
ls -lt pci/pci* ,etc
rmmod amd8131_edac
rmmod amd8111_edac

Test results:
-------------

root@localhost:/> insmod edac_core.ko
root@localhost:/> dmesg -n 8
root@localhost:/> insmod amd8111_edac.ko
AMD8111 EDAC driver Ver: 1.0.0 Mar 11 2009
(c) 2008 Wind River Systems, Inc.
EDAC DEBUG: edac_device_register_sysfs_main_kobj()
amd8111_lpc_bridge_init: port 97 is buggy, not supported by hardware?
EDAC DEBUG: edac_device_add_device()
EDAC DEBUG: find_edac_device_by_dev()
EDAC DEBUG: edac_device_create_sysfs() idx=0
EDAC DEBUG: edac_device_create_instances()
EDAC DEBUG: edac_device_workq_setup()
EDAC DEVICE0: Giving out device to module 'amd8111_edac' controller 'lpc': DEV '0000:00:06.0' (POLLED)
added one edac_dev on AMD8111 vendor 1022, device 7468, name lpc
EDAC DEBUG: edac_pci_alloc_ctl_info()
EDAC DEBUG: edac_pci_add_device()
EDAC DEBUG: add_edac_pci_to_global_list()
EDAC DEBUG: find_edac_pci_by_dev()
EDAC DEBUG: edac_pci_create_sysfs() idx=0
EDAC DEBUG: edac_pci_main_kobj_setup()
EDAC DEBUG: Registered '.../edac/pci' kobject
EDAC DEBUG: edac_pci_create_instance_kobj()
EDAC DEBUG: edac_pci_create_instance_kobj() Register instance 'pci0' kobject
EDAC DEBUG: edac_pci_workq_setup()
EDAC PCI0: Giving out device to module 'amd8111_edac' controller 'AMD8111_PCI_Controller': DEV '0000:00:05.0' (POLLED)
added one edac_pci on AMD8111 vendor 1022, device 7460, name AMD8111_PCI_Controller
root@localhost:/> insmod amd8131_edac.ko
AMD8131 EDAC driver Ver: 1.0.0 Mar 11 2009
(c) 2008 Wind River Systems, Inc.
EDAC DEBUG: edac_pci_alloc_ctl_info()
EDAC DEBUG: edac_pci_add_device()
EDAC DEBUG: add_edac_pci_to_global_list()
EDAC DEBUG: find_edac_pci_by_dev()
EDAC DEBUG: edac_pci_create_sysfs() idx=1
EDAC DEBUG: edac_pci_main_kobj_setup()
EDAC DEBUG: edac_pci_create_instance_kobj()
EDAC DEBUG: edac_pci_create_instance_kobj() Register instance 'pci1' kobject
EDAC DEBUG: edac_pci_workq_setup()
EDAC PCI1: Giving out device to module 'amd8131_edac' controller 'AMD8131_PCIX_NORTH_A': DEV '0000:00:01.0' (POLLED)
added one device on AMD8131 vendor 1022, device 7451, devfn 8, name AMD8131_PCIX_NORTH_A
EDAC DEBUG: edac_pci_alloc_ctl_info()
EDAC DEBUG: edac_pci_add_device()
EDAC DEBUG: add_edac_pci_to_global_list()
EDAC DEBUG: find_edac_pci_by_dev()
EDAC DEBUG: edac_pci_create_sysfs() idx=2
EDAC DEBUG: edac_pci_main_kobj_setup()
EDAC DEBUG: edac_pci_create_instance_kobj()
EDAC DEBUG: edac_pci_create_instance_kobj() Register instance 'pci2' kobject
EDAC DEBUG: edac_pci_workq_setup()
EDAC PCI2: Giving out device to module 'amd8131_edac' controller 'AMD8131_PCIX_NORTH_B': DEV '0000:00:02.0' (POLLED)
added one device on AMD8131 vendor 1022, device 7451, devfn 10, name AMD8131_PCIX_NORTH_B
EDAC DEBUG: edac_pci_alloc_ctl_info()
EDAC DEBUG: edac_pci_add_device()
EDAC DEBUG: add_edac_pci_to_global_list()
EDAC DEBUG: find_edac_pci_by_dev()
EDAC DEBUG: edac_pci_create_sysfs() idx=3
EDAC DEBUG: edac_pci_main_kobj_setup()
EDAC DEBUG: edac_pci_create_instance_kobj()
EDAC DEBUG: edac_pci_create_instance_kobj() Register instance 'pci3' kobject
EDAC DEBUG: edac_pci_workq_setup()
EDAC PCI3: Giving out device to module 'amd8131_edac' controller 'AMD8131_PCIX_SOUTH_A': DEV '0000:00:03.0' (POLLED)
added one device on AMD8131 vendor 1022, device 7451, devfn 18, name AMD8131_PCIX_SOUTH_A
EDAC DEBUG: edac_pci_alloc_ctl_info()
EDAC DEBUG: edac_pci_add_device()
EDAC DEBUG: add_edac_pci_to_global_list()
EDAC DEBUG: find_edac_pci_by_dev()
EDAC DEBUG: edac_pci_create_sysfs() idx=4
EDAC DEBUG: edac_pci_main_kobj_setup()
EDAC DEBUG: edac_pci_create_instance_kobj()
EDAC DEBUG: edac_pci_create_instance_kobj() Register instance 'pci4' kobject
EDAC DEBUG: edac_pci_workq_setup()
EDAC PCI4: Giving out device to module 'amd8131_edac' controller 'AMD8131_PCIX_SOUTH_B': DEV '0000:00:04.0' (POLLED)
added one device on AMD8131 vendor 1022, device 7451, devfn 20, name AMD8131_PCIX_SOUTH_B
root@localhost:/>
root@localhost:/> cd /sys/devices/system/edac/
root@localhost:/sys/devices/system/edac> ls -lt
total 0
drwxr-xr-x 3 root root 0 Oct 30 06:31 lpc
drwxr-xr-x 2 root root 0 Oct 30 06:31 mc
drwxr-xr-x 7 root root 0 Oct 30 06:31 pci
root@localhost:/sys/devices/system/edac> ls -lt lpc
total 0
lrwxrwxrwx 1 root root 0 Oct 30 06:31 device -> ../../../pci0000:00/0000:00:06.0
-rw-r--r-- 1 root root 4096 Oct 30 06:31 log_ce
-rw-r--r-- 1 root root 4096 Oct 30 06:31 log_ue
drwxr-xr-x 2 root root 0 Oct 30 06:31 lpc0
-rw-r--r-- 1 root root 4096 Oct 30 06:31 panic_on_ue
-rw-r--r-- 1 root root 4096 Oct 30 06:31 poll_msec
root@localhost:/sys/devices/system/edac> cd lpc
root@localhost:/sys/devices/system/edac/lpc> cat log_ce
1
root@localhost:/sys/devices/system/edac/lpc> cat log_ue
1
root@localhost:/sys/devices/system/edac/lpc> cat panic_on_ue
0
root@localhost:/sys/devices/system/edac/lpc> echo 1 > panic_on_ue
root@localhost:/sys/devices/system/edac/lpc> cat panic_on_ue
1
root@localhost:/sys/devices/system/edac/lpc> cat poll_msec
1000
root@localhost:/sys/devices/system/edac/lpc> cd lpc0/
root@localhost:/sys/devices/system/edac/lpc/lpc0> ls -lt
total 0
-r--r--r-- 1 root root 4096 Oct 30 06:32 ce_count
-r--r--r-- 1 root root 4096 Oct 30 06:32 ue_count
root@localhost:/sys/devices/system/edac/lpc/lpc0> cat ce_count
0
root@localhost:/sys/devices/system/edac/lpc/lpc0> cat ue_count
0
root@localhost:/sys/devices/system/edac/lpc/lpc0> cd ../..
root@localhost:/sys/devices/system/edac> cd pci
root@localhost:/sys/devices/system/edac/pci> ls -lt
total 0
-rw-r--r-- 1 root root 4096 Oct 30 06:32 check_pci_errors
-rw-r--r-- 1 root root 4096 Oct 30 06:32 edac_pci_log_npe
-rw-r--r-- 1 root root 4096 Oct 30 06:32 edac_pci_log_pe
-rw-r--r-- 1 root root 4096 Oct 30 06:32 edac_pci_panic_on_pe
drwxr-xr-x 2 root root 0 Oct 30 06:32 pci0
drwxr-xr-x 2 root root 0 Oct 30 06:32 pci1
drwxr-xr-x 2 root root 0 Oct 30 06:32 pci2
drwxr-xr-x 2 root root 0 Oct 30 06:32 pci3
drwxr-xr-x 2 root root 0 Oct 30 06:32 pci4
-r--r--r-- 1 root root 4096 Oct 30 06:32 pci_nonparity_count
-r--r--r-- 1 root root 4096 Oct 30 06:32 pci_parity_count
root@localhost:/sys/devices/system/edac/pci> cat check_pci_errors
0
root@localhost:/sys/devices/system/edac/pci> echo 1 > check_pci_errors
root@localhost:/sys/devices/system/edac/pci> cat check_pci_errors
1
root@localhost:/sys/devices/system/edac/pci> cat edac_pci_log_npe
1
root@localhost:/sys/devices/system/edac/pci> cat edac_pci_log_pe
1
root@localhost:/sys/devices/system/edac/pci> cat edac_pci_panic_on_pe
0
root@localhost:/sys/devices/system/edac/pci> echo 1 > edac_pci_panic_on_pe
root@localhost:/sys/devices/system/edac/pci> cat edac_pci_panic_on_pe
1
root@localhost:/sys/devices/system/edac/pci> cat pci_nonparity_count
0
root@localhost:/sys/devices/system/edac/pci> cat pci_parity_count
0
root@localhost:/sys/devices/system/edac/pci> ls -lt
total 0
-rw-r--r-- 1 root root 4096 Oct 30 06:32 edac_pci_panic_on_pe
-rw-r--r-- 1 root root 4096 Oct 30 06:32 check_pci_errors
-rw-r--r-- 1 root root 4096 Oct 30 06:32 edac_pci_log_npe
-rw-r--r-- 1 root root 4096 Oct 30 06:32 edac_pci_log_pe
drwxr-xr-x 2 root root 0 Oct 30 06:32 pci0
drwxr-xr-x 2 root root 0 Oct 30 06:32 pci1
drwxr-xr-x 2 root root 0 Oct 30 06:32 pci2
drwxr-xr-x 2 root root 0 Oct 30 06:32 pci3
drwxr-xr-x 2 root root 0 Oct 30 06:32 pci4
-r--r--r-- 1 root root 4096 Oct 30 06:32 pci_nonparity_count
-r--r--r-- 1 root root 4096 Oct 30 06:32 pci_parity_count
root@localhost:/sys/devices/system/edac/pci> ls -lt pci0
total 0
lrwxrwxrwx 1 root root 0 Oct 30 06:33 device -> ../../../../pci0000:00/0000:00:05.0
-r--r--r-- 1 root root 4096 Oct 30 06:33 npe_count
-r--r--r-- 1 root root 4096 Oct 30 06:33 pe_count
root@localhost:/sys/devices/system/edac/pci> cat pci0/npe_count
0
root@localhost:/sys/devices/system/edac/pci> cat pci0/pe_count
0
root@localhost:/sys/devices/system/edac/pci> ls -lt pci*
-r--r--r-- 1 root root 4096 Oct 30 06:32 pci_nonparity_count
-r--r--r-- 1 root root 4096 Oct 30 06:32 pci_parity_count

pci0:
total 0
lrwxrwxrwx 1 root root 0 Oct 30 06:33 device -> ../../../../pci0000:00/0000:00:05.0
-r--r--r-- 1 root root 4096 Oct 30 06:33 npe_count
-r--r--r-- 1 root root 4096 Oct 30 06:33 pe_count

pci1:
total 0
lrwxrwxrwx 1 root root 0 Oct 30 06:33 device -> ../../../../pci0000:00/0000:00:01.0
-r--r--r-- 1 root root 4096 Oct 30 06:33 npe_count
-r--r--r-- 1 root root 4096 Oct 30 06:33 pe_count

pci2:
total 0
lrwxrwxrwx 1 root root 0 Oct 30 06:33 device -> ../../../../pci0000:00/0000:00:02.0
-r--r--r-- 1 root root 4096 Oct 30 06:33 npe_count
-r--r--r-- 1 root root 4096 Oct 30 06:33 pe_count

pci3:
total 0
lrwxrwxrwx 1 root root 0 Oct 30 06:33 device -> ../../../../pci0000:00/0000:00:03.0
-r--r--r-- 1 root root 4096 Oct 30 06:33 npe_count
-r--r--r-- 1 root root 4096 Oct 30 06:33 pe_count

pci4:
total 0
lrwxrwxrwx 1 root root 0 Oct 30 06:33 device -> ../../../../pci0000:00/0000:00:04.0
-r--r--r-- 1 root root 4096 Oct 30 06:33 npe_count
-r--r--r-- 1 root root 4096 Oct 30 06:33 pe_count
root@localhost:/sys/devices/system/edac/pci> cd ..
root@localhost:/sys/devices/system/edac> lsmod
Module Size Used by
amd8131_edac 7456 0
amd8111_edac 12476 0
edac_core 82664 4 amd8131_edac,amd8111_edac
root@localhost:/sys/devices/system/edac> rmmod amd8111_edac
EDAC DEBUG: edac_pci_del_device()
EDAC DEBUG: find_edac_pci_by_dev()
EDAC DEBUG: edac_pci_workq_teardown()
EDAC PCI: Removed device 0 for amd8111_edac AMD8111_PCI_Controller: DEV 0000:00:05.0
EDAC DEBUG: edac_pci_free_ctl_info()
EDAC DEBUG: edac_pci_remove_sysfs() index=0
EDAC DEBUG: edac_pci_unregister_sysfs_instance_kobj()
EDAC DEBUG: edac_pci_instance_release()
EDAC DEBUG: edac_pci_remove_sysfs() calling edac_pci_main_kobj_teardown()
EDAC DEBUG: edac_pci_main_kobj_teardown()
EDAC DEBUG: edac_device_del_device()
EDAC DEBUG: find_edac_device_by_dev()
EDAC DEBUG: edac_device_remove_sysfs()
EDAC DEBUG: edac_device_ctrl_instance_release()
EDAC MC: Removed device 0 for amd8111_edac lpc: DEV 0000:00:06.0
EDAC DEBUG: edac_device_unregister_sysfs_main_kobj()
root@localhost:/sys/devices/system/edac> ls -lt
total 0
drwxr-xr-x 6 root root 0 Oct 30 06:33 pci
drwxr-xr-x 2 root root 0 Oct 30 06:31 mc
root@localhost:/sys/devices/system/edac> ls -lt pci
total 0
-rw-r--r-- 1 root root 4096 Oct 30 06:32 edac_pci_panic_on_pe
-rw-r--r-- 1 root root 4096 Oct 30 06:32 check_pci_errors
-rw-r--r-- 1 root root 4096 Oct 30 06:32 edac_pci_log_npe
-rw-r--r-- 1 root root 4096 Oct 30 06:32 edac_pci_log_pe
drwxr-xr-x 2 root root 0 Oct 30 06:32 pci1
drwxr-xr-x 2 root root 0 Oct 30 06:32 pci2
drwxr-xr-x 2 root root 0 Oct 30 06:32 pci3
drwxr-xr-x 2 root root 0 Oct 30 06:32 pci4
-r--r--r-- 1 root root 4096 Oct 30 06:32 pci_nonparity_count
-r--r--r-- 1 root root 4096 Oct 30 06:32 pci_parity_count
root@localhost:/sys/devices/system/edac> rmmod amd8131_edac
EDAC DEBUG: edac_pci_del_device()
EDAC DEBUG: find_edac_pci_by_dev()
EDAC DEBUG: edac_pci_workq_teardown()
EDAC PCI: Removed device 4 for amd8131_edac AMD8131_PCIX_SOUTH_B: DEV 0000:00:04.0
EDAC DEBUG: edac_pci_free_ctl_info()
EDAC DEBUG: edac_pci_remove_sysfs() index=4
EDAC DEBUG: edac_pci_unregister_sysfs_instance_kobj()
EDAC DEBUG: edac_pci_instance_release()
EDAC DEBUG: edac_pci_remove_sysfs() calling edac_pci_main_kobj_teardown()
EDAC DEBUG: edac_pci_main_kobj_teardown()
EDAC DEBUG: edac_pci_del_device()
EDAC DEBUG: find_edac_pci_by_dev()
EDAC DEBUG: edac_pci_workq_teardown()
EDAC PCI: Removed device 3 for amd8131_edac AMD8131_PCIX_SOUTH_A: DEV 0000:00:03.0
EDAC DEBUG: edac_pci_free_ctl_info()
EDAC DEBUG: edac_pci_remove_sysfs() index=3
EDAC DEBUG: edac_pci_unregister_sysfs_instance_kobj()
EDAC DEBUG: edac_pci_instance_release()
EDAC DEBUG: edac_pci_remove_sysfs() calling edac_pci_main_kobj_teardown()
EDAC DEBUG: edac_pci_main_kobj_teardown()
EDAC DEBUG: edac_pci_del_device()
EDAC DEBUG: find_edac_pci_by_dev()
EDAC DEBUG: edac_pci_workq_teardown()
EDAC PCI: Removed device 2 for amd8131_edac AMD8131_PCIX_NORTH_B: DEV 0000:00:02.0
EDAC DEBUG: edac_pci_free_ctl_info()
EDAC DEBUG: edac_pci_remove_sysfs() index=2
EDAC DEBUG: edac_pci_unregister_sysfs_instance_kobj()
EDAC DEBUG: edac_pci_instance_release()
EDAC DEBUG: edac_pci_remove_sysfs() calling edac_pci_main_kobj_teardown()
EDAC DEBUG: edac_pci_main_kobj_teardown()
EDAC DEBUG: edac_pci_del_device()
EDAC DEBUG: find_edac_pci_by_dev()
EDAC DEBUG: edac_pci_workq_teardown()
EDAC PCI: Removed device 1 for amd8131_edac AMD8131_PCIX_NORTH_A: DEV 0000:00:01.0
EDAC DEBUG: edac_pci_free_ctl_info()
EDAC DEBUG: edac_pci_remove_sysfs() index=1
EDAC DEBUG: edac_pci_unregister_sysfs_instance_kobj()
EDAC DEBUG: edac_pci_instance_release()
EDAC DEBUG: edac_pci_remove_sysfs() calling edac_pci_main_kobj_teardown()
EDAC DEBUG: edac_pci_main_kobj_teardown()
EDAC DEBUG: edac_pci_main_kobj_teardown() called kobject_put on main kobj
EDAC DEBUG: edac_pci_release_main_kobj() here to module_put(THIS_MODULE)
root@localhost:/sys/devices/system/edac> ls -lt
total 0
drwxr-xr-x 2 root root 0 Oct 30 06:31 mc
root@localhost:/sys/devices/system/edac> rmmod edac_core
EDAC DEBUG: edac_exit()
root@localhost:/sys/devices/system/edac> ls -lt
total 0
root@localhost:/sys/devices/system/edac> lsmod
Module Size Used by
root@localhost:/sys/devices/system/edac>


diffstat:
---------
0001-EDAC-AMD8111-driver-header-file.patch
drivers/edac/amd8111_edac.h | 130 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 130 insertions(+), 0 deletions(-)
create mode 100644 drivers/edac/amd8111_edac.h

0002-EDAC-AMD8111-driver-source-file.patch
drivers/edac/amd8111_edac.c | 580 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 580 insertions(+), 0 deletions(-)
create mode 100644 drivers/edac/amd8111_edac.c

0003-EDAC-AMD8111-driver-Kconfig-Makefile.patch
drivers/edac/Kconfig | 7 +++++++
drivers/edac/Makefile | 1 +
2 files changed, 8 insertions(+), 0 deletions(-)

0004-EDAC-Add-edac_pci_alloc_index.patch
drivers/edac/edac_core.h | 1 +
drivers/edac/edac_pci.c | 14 ++++++++++++++
2 files changed, 15 insertions(+), 0 deletions(-)

0005-EDAC-AMD8131-driver-header-file.patch
drivers/edac/amd8131_edac.h | 119 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 119 insertions(+), 0 deletions(-)
create mode 100644 drivers/edac/amd8131_edac.h

0006-EDAC-AMD8131-driver-souce-file.patch
drivers/edac/amd8131_edac.c | 370 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 370 insertions(+), 0 deletions(-)
create mode 100644 drivers/edac/amd8131_edac.c

0007-EDAC-AMD8131-driver-Kconfig-Makefile.patch
drivers/edac/Kconfig | 7 +++++++
drivers/edac/Makefile | 1 +
2 files changed, 8 insertions(+), 0 deletions(-)


2009-03-11 03:38:50

by Harry Ciao

[permalink] [raw]
Subject: [v2 PATCH 1/7] EDAC: AMD8111 driver header file

Introduce AMD8111 EDAC driver header file, which adds register and bits
definitions for the LPC Bridge Controller and PCI Bridge Controller on
the AMD8111 HyperTransport I/O Hub.

Signed-off-by: Harry Ciao <[email protected]>
---
drivers/edac/amd8111_edac.h | 130 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 130 insertions(+), 0 deletions(-)
create mode 100644 drivers/edac/amd8111_edac.h

diff --git a/drivers/edac/amd8111_edac.h b/drivers/edac/amd8111_edac.h
new file mode 100644
index 0000000..ef9eb36
--- /dev/null
+++ b/drivers/edac/amd8111_edac.h
@@ -0,0 +1,130 @@
+/*
+ * amd8111_edac.h, EDAC defs for AMD8111 hypertransport chip
+ *
+ * Copyright (c) 2008 Wind River Systems, Inc.
+ *
+ * Authors: Cao Qingtao <[email protected]>
+ * Benjamin Walsh <[email protected]>
+ * Hu Yongqi <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _AMD8111_EDAC_H_
+#define _AMD8111_EDAC_H_
+
+/************************************************************
+ * PCI Bridge Status and Command Register, DevA:0x04
+ ************************************************************/
+#define REG_PCI_STSCMD 0x04
+enum pci_stscmd_bits {
+ PCI_STSCMD_SSE = BIT(30),
+ PCI_STSCMD_RMA = BIT(29),
+ PCI_STSCMD_RTA = BIT(28),
+ PCI_STSCMD_SERREN = BIT(8),
+ PCI_STSCMD_CLEAR_MASK = (PCI_STSCMD_SSE |
+ PCI_STSCMD_RMA |
+ PCI_STSCMD_RTA)
+};
+
+/************************************************************
+ * PCI Bridge Memory Base-Limit Register, DevA:0x1c
+ ************************************************************/
+#define REG_MEM_LIM 0x1c
+enum mem_limit_bits {
+ MEM_LIMIT_DPE = BIT(31),
+ MEM_LIMIT_RSE = BIT(30),
+ MEM_LIMIT_RMA = BIT(29),
+ MEM_LIMIT_RTA = BIT(28),
+ MEM_LIMIT_STA = BIT(27),
+ MEM_LIMIT_MDPE = BIT(24),
+ MEM_LIMIT_CLEAR_MASK = (MEM_LIMIT_DPE |
+ MEM_LIMIT_RSE |
+ MEM_LIMIT_RMA |
+ MEM_LIMIT_RTA |
+ MEM_LIMIT_STA |
+ MEM_LIMIT_MDPE)
+};
+
+/************************************************************
+ * HyperTransport Link Control Register, DevA:0xc4
+ ************************************************************/
+#define REG_HT_LINK 0xc4
+enum ht_link_bits {
+ HT_LINK_LKFAIL = BIT(4),
+ HT_LINK_CRCFEN = BIT(1),
+ HT_LINK_CLEAR_MASK = (HT_LINK_LKFAIL)
+};
+
+/************************************************************
+ * PCI Bridge Interrupt and Bridge Control, DevA:0x3c
+ ************************************************************/
+#define REG_PCI_INTBRG_CTRL 0x3c
+enum pci_intbrg_ctrl_bits {
+ PCI_INTBRG_CTRL_DTSERREN = BIT(27),
+ PCI_INTBRG_CTRL_DTSTAT = BIT(26),
+ PCI_INTBRG_CTRL_MARSP = BIT(21),
+ PCI_INTBRG_CTRL_SERREN = BIT(17),
+ PCI_INTBRG_CTRL_PEREN = BIT(16),
+ PCI_INTBRG_CTRL_CLEAR_MASK = (PCI_INTBRG_CTRL_DTSTAT),
+ PCI_INTBRG_CTRL_POLL_MASK = (PCI_INTBRG_CTRL_DTSERREN |
+ PCI_INTBRG_CTRL_MARSP |
+ PCI_INTBRG_CTRL_SERREN)
+};
+
+/************************************************************
+ * I/O Control 1 Register, DevB:0x40
+ ************************************************************/
+#define REG_IO_CTRL_1 0x40
+enum io_ctrl_1_bits {
+ IO_CTRL_1_NMIONERR = BIT(7),
+ IO_CTRL_1_LPC_ERR = BIT(6),
+ IO_CTRL_1_PW2LPC = BIT(1),
+ IO_CTRL_1_CLEAR_MASK = (IO_CTRL_1_LPC_ERR | IO_CTRL_1_PW2LPC)
+};
+
+/************************************************************
+ * Legacy I/O Space Registers
+ ************************************************************/
+#define REG_AT_COMPAT 0x61
+enum at_compat_bits {
+ AT_COMPAT_SERR = BIT(7),
+ AT_COMPAT_IOCHK = BIT(6),
+ AT_COMPAT_CLRIOCHK = BIT(3),
+ AT_COMPAT_CLRSERR = BIT(2),
+};
+
+struct amd8111_dev_info {
+ u16 err_dev; /* PCI Device ID */
+ struct pci_dev *dev;
+ int edac_idx; /* device index */
+ const char *ctl_name;
+ struct edac_device_ctl_info *edac_dev;
+ void (*init)(struct amd8111_dev_info *dev_info);
+ void (*exit)(struct amd8111_dev_info *dev_info);
+ void (*check)(struct edac_device_ctl_info *edac_dev);
+};
+
+struct amd8111_pci_info {
+ u16 err_dev; /* PCI Device ID */
+ struct pci_dev *dev;
+ int edac_idx; /* pci index */
+ const char *ctl_name;
+ struct edac_pci_ctl_info *edac_dev;
+ void (*init)(struct amd8111_pci_info *dev_info);
+ void (*exit)(struct amd8111_pci_info *dev_info);
+ void (*check)(struct edac_pci_ctl_info *edac_dev);
+};
+
+#endif /* _AMD8111_EDAC_H_ */
--
1.5.6.2

2009-03-11 03:39:42

by Harry Ciao

[permalink] [raw]
Subject: [v2 PATCH 4/7] EDAC: Add edac_pci_alloc_index()

Add edac_pci_alloc_index(), because for MAPLE platform there may
exist several EDAC driver modules that could make use of
edac_pci_ctl_info structure at the same time. The index allocation
for these structures should be taken care of by EDAC core.

Signed-off-by: Harry Ciao <[email protected]>
---
drivers/edac/edac_core.h | 1 +
drivers/edac/edac_pci.c | 14 ++++++++++++++
2 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
index 4b55ec6..76cb7c2 100644
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
@@ -831,6 +831,7 @@ extern void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci);
extern void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
unsigned long value);

+extern int edac_pci_alloc_index(void);
extern int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx);
extern struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev);

diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c
index 5d3c808..5b150ae 100644
--- a/drivers/edac/edac_pci.c
+++ b/drivers/edac/edac_pci.c
@@ -30,6 +30,7 @@

static DEFINE_MUTEX(edac_pci_ctls_mutex);
static LIST_HEAD(edac_pci_list);
+static atomic_t pci_indexes = ATOMIC_INIT(0);

/*
* edac_pci_alloc_ctl_info
@@ -318,6 +319,19 @@ void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
EXPORT_SYMBOL_GPL(edac_pci_reset_delay_period);

/*
+ * edac_pci_alloc_index: Allocate a unique PCI index number
+ *
+ * Return:
+ * allocated index number
+ *
+ */
+int edac_pci_alloc_index(void)
+{
+ return atomic_inc_return(&pci_indexes) - 1;
+}
+EXPORT_SYMBOL_GPL(edac_pci_alloc_index);
+
+/*
* edac_pci_add_device: Insert the 'edac_dev' structure into the
* edac_pci global list and create sysfs entries associated with
* edac_pci structure.
--
1.5.6.2

2009-03-11 03:39:26

by Harry Ciao

[permalink] [raw]
Subject: [v2 PATCH 5/7] EDAC: AMD8131 driver header file

Introduce AMD8131 EDAC driver header file, which adds register and bits
definitions for the PCI-X Bridge Controller on the AMD8131 HyperTransport
I/O Hub.

Signed-off-by: Harry Ciao <[email protected]>
---
drivers/edac/amd8131_edac.h | 119 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 119 insertions(+), 0 deletions(-)
create mode 100644 drivers/edac/amd8131_edac.h

diff --git a/drivers/edac/amd8131_edac.h b/drivers/edac/amd8131_edac.h
new file mode 100644
index 0000000..60e0d1c
--- /dev/null
+++ b/drivers/edac/amd8131_edac.h
@@ -0,0 +1,119 @@
+/*
+ * amd8131_edac.h, EDAC defs for AMD8131 hypertransport chip
+ *
+ * Copyright (c) 2008 Wind River Systems, Inc.
+ *
+ * Authors: Cao Qingtao <[email protected]>
+ * Benjamin Walsh <[email protected]>
+ * Hu Yongqi <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _AMD8131_EDAC_H_
+#define _AMD8131_EDAC_H_
+
+#define DEVFN_PCIX_BRIDGE_NORTH_A 8
+#define DEVFN_PCIX_BRIDGE_NORTH_B 16
+#define DEVFN_PCIX_BRIDGE_SOUTH_A 24
+#define DEVFN_PCIX_BRIDGE_SOUTH_B 32
+
+/************************************************************
+ * PCI-X Bridge Status and Command Register, DevA:0x04
+ ************************************************************/
+#define REG_STS_CMD 0x04
+enum sts_cmd_bits {
+ STS_CMD_SSE = BIT(30),
+ STS_CMD_SERREN = BIT(8)
+};
+
+/************************************************************
+ * PCI-X Bridge Interrupt and Bridge Control Register,
+ ************************************************************/
+#define REG_INT_CTLR 0x3c
+enum int_ctlr_bits {
+ INT_CTLR_DTSE = BIT(27),
+ INT_CTLR_DTS = BIT(26),
+ INT_CTLR_SERR = BIT(17),
+ INT_CTLR_PERR = BIT(16)
+};
+
+/************************************************************
+ * PCI-X Bridge Memory Base-Limit Register, DevA:0x1C
+ ************************************************************/
+#define REG_MEM_LIM 0x1c
+enum mem_limit_bits {
+ MEM_LIMIT_DPE = BIT(31),
+ MEM_LIMIT_RSE = BIT(30),
+ MEM_LIMIT_RMA = BIT(29),
+ MEM_LIMIT_RTA = BIT(28),
+ MEM_LIMIT_STA = BIT(27),
+ MEM_LIMIT_MDPE = BIT(24),
+ MEM_LIMIT_MASK = MEM_LIMIT_DPE|MEM_LIMIT_RSE|MEM_LIMIT_RMA|
+ MEM_LIMIT_RTA|MEM_LIMIT_STA|MEM_LIMIT_MDPE
+};
+
+/************************************************************
+ * Link Configuration And Control Register, side A
+ ************************************************************/
+#define REG_LNK_CTRL_A 0xc4
+
+/************************************************************
+ * Link Configuration And Control Register, side B
+ ************************************************************/
+#define REG_LNK_CTRL_B 0xc8
+
+enum lnk_ctrl_bits {
+ LNK_CTRL_CRCERR_A = BIT(9),
+ LNK_CTRL_CRCERR_B = BIT(8),
+ LNK_CTRL_CRCFEN = BIT(1)
+};
+
+enum pcix_bridge_inst {
+ NORTH_A = 0,
+ NORTH_B = 1,
+ SOUTH_A = 2,
+ SOUTH_B = 3,
+ NO_BRIDGE = 4
+};
+
+struct amd8131_dev_info {
+ int devfn;
+ enum pcix_bridge_inst inst;
+ struct pci_dev *dev;
+ int edac_idx; /* pci device index */
+ char *ctl_name;
+ struct edac_pci_ctl_info *edac_dev;
+};
+
+/*
+ * AMD8131 chipset has two pairs of PCIX Bridge and related IOAPIC
+ * Controler, and ATCA-6101 has two AMD8131 chipsets, so there are
+ * four PCIX Bridges on ATCA-6101 altogether.
+ *
+ * These PCIX Bridges share the same PCI Device ID and are all of
+ * Function Zero, they could be discrimated by their pci_dev->devfn.
+ * They share the same set of init/check/exit methods, and their
+ * private structures are collected in the devices[] array.
+ */
+struct amd8131_info {
+ u16 err_dev; /* PCI Device ID for AMD8131 APIC*/
+ struct amd8131_dev_info *devices;
+ void (*init)(struct amd8131_dev_info *dev_info);
+ void (*exit)(struct amd8131_dev_info *dev_info);
+ void (*check)(struct edac_pci_ctl_info *edac_dev);
+};
+
+#endif /* _AMD8131_EDAC_H_ */
+
--
1.5.6.2

2009-03-11 03:39:58

by Harry Ciao

[permalink] [raw]
Subject: [v2 PATCH 3/7] EDAC: AMD8111 driver Kconfig and Makefile

Introduce Kconfig and Makefile options for AMD8111 EDAC driver.

Signed-off-by: Harry Ciao <[email protected]>
---
drivers/edac/Kconfig | 7 +++++++
drivers/edac/Makefile | 1 +
2 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index eee47fd..46f8e77 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -174,4 +174,11 @@ config EDAC_CELL
Cell Broadband Engine internal memory controller
on platform without a hypervisor

+config EDAC_AMD8111
+ tristate "AMD8111 HyperTransport I/O Hub"
+ depends on EDAC_MM_EDAC && PCI
+ help
+ Support for error detection and correction on the
+ AMD8111 HyperTransport I/O Hub chip.
+
endif # EDAC
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index b751969..c324956 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -34,4 +34,5 @@ obj-$(CONFIG_EDAC_PASEMI) += pasemi_edac.o
obj-$(CONFIG_EDAC_MPC85XX) += mpc85xx_edac.o
obj-$(CONFIG_EDAC_MV64X60) += mv64x60_edac.o
obj-$(CONFIG_EDAC_CELL) += cell_edac.o
+obj-$(CONFIG_EDAC_AMD8111) += amd8111_edac.o

--
1.5.6.2

2009-03-11 03:40:49

by Harry Ciao

[permalink] [raw]
Subject: [v2 PATCH 2/7] EDAC: AMD8111 driver source file

Introduce AMD8111 EDAC driver source file, which makes use of error
detections on the LPC Bridge Controller and PCI Bridge Controller on
the AMD8111 HyperTransport I/O Hub.

Signed-off-by: Harry Ciao <[email protected]>
---
drivers/edac/amd8111_edac.c | 595 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 595 insertions(+), 0 deletions(-)
create mode 100644 drivers/edac/amd8111_edac.c

diff --git a/drivers/edac/amd8111_edac.c b/drivers/edac/amd8111_edac.c
new file mode 100644
index 0000000..5808e4a
--- /dev/null
+++ b/drivers/edac/amd8111_edac.c
@@ -0,0 +1,595 @@
+/*
+ * amd8111_edac.c, AMD8111 Hyper Transport chip EDAC kernel module
+ *
+ * Copyright (c) 2008 Wind River Systems, Inc.
+ *
+ * Authors: Cao Qingtao <[email protected]>
+ * Benjamin Walsh <[email protected]>
+ * Hu Yongqi <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/edac.h>
+#include <linux/pci_ids.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+#include "amd8111_edac.h"
+
+#define AMD8111_EDAC_REVISION " Ver: 1.0.0 " __DATE__
+#define AMD8111_EDAC_MOD_STR "amd8111_edac"
+
+#define PCI_DEVICE_ID_AMD_8111_PCI 0x7460
+static int edac_dev_idx;
+
+enum amd8111_edac_devs {
+ LPC_BRIDGE = 0,
+};
+
+enum amd8111_edac_pcis {
+ PCI_BRIDGE = 0,
+};
+
+/* Wrapper functions for accessing PCI configuration space */
+static int edac_pci_read_dword(struct pci_dev *dev, int reg, u32 *val32)
+{
+ int ret;
+
+ ret = pci_read_config_dword(dev, reg, val32);
+ if (ret != 0)
+ printk(KERN_ERR AMD8111_EDAC_MOD_STR
+ " PCI Access Read Error at 0x%x\n", reg);
+
+ return ret;
+}
+
+static void edac_pci_read_byte(struct pci_dev *dev, int reg, u8 *val8)
+{
+ int ret;
+
+ ret = pci_read_config_byte(dev, reg, val8);
+ if (ret != 0)
+ printk(KERN_ERR AMD8111_EDAC_MOD_STR
+ " PCI Access Read Error at 0x%x\n", reg);
+}
+
+static void edac_pci_write_dword(struct pci_dev *dev, int reg, u32 val32)
+{
+ int ret;
+
+ ret = pci_write_config_dword(dev, reg, val32);
+ if (ret != 0)
+ printk(KERN_ERR AMD8111_EDAC_MOD_STR
+ " PCI Access Write Error at 0x%x\n", reg);
+}
+
+static void edac_pci_write_byte(struct pci_dev *dev, int reg, u8 val8)
+{
+ int ret;
+
+ ret = pci_write_config_byte(dev, reg, val8);
+ if (ret != 0)
+ printk(KERN_ERR AMD8111_EDAC_MOD_STR
+ " PCI Access Write Error at 0x%x\n", reg);
+}
+
+/*
+ * device-specific methods for amd8111 PCI Bridge Controller
+ *
+ * Error Reporting and Handling for amd8111 chipset could be found
+ * in its datasheet 3.1.2 section, P37
+ */
+static void amd8111_pci_bridge_init(struct amd8111_pci_info *pci_info)
+{
+ u32 val32;
+ struct pci_dev *dev = pci_info->dev;
+
+ /* First clear error detection flags on the host interface */
+
+ /* Clear SSE/SMA/STA flags in the global status register*/
+ edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32);
+ if (val32 & PCI_STSCMD_CLEAR_MASK)
+ edac_pci_write_dword(dev, REG_PCI_STSCMD, val32);
+
+ /* Clear CRC and Link Fail flags in HT Link Control reg */
+ edac_pci_read_dword(dev, REG_HT_LINK, &val32);
+ if (val32 & HT_LINK_CLEAR_MASK)
+ edac_pci_write_dword(dev, REG_HT_LINK, val32);
+
+ /* Second clear all fault on the secondary interface */
+
+ /* Clear error flags in the memory-base limit reg. */
+ edac_pci_read_dword(dev, REG_MEM_LIM, &val32);
+ if (val32 & MEM_LIMIT_CLEAR_MASK)
+ edac_pci_write_dword(dev, REG_MEM_LIM, val32);
+
+ /* Clear Discard Timer Expired flag in Interrupt/Bridge Control reg */
+ edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);
+ if (val32 & PCI_INTBRG_CTRL_CLEAR_MASK)
+ edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);
+
+ /* Last enable error detections */
+ if (edac_op_state == EDAC_OPSTATE_POLL) {
+ /* Enable System Error reporting in global status register */
+ edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32);
+ val32 |= PCI_STSCMD_SERREN;
+ edac_pci_write_dword(dev, REG_PCI_STSCMD, val32);
+
+ /* Enable CRC Sync flood packets to HyperTransport Link */
+ edac_pci_read_dword(dev, REG_HT_LINK, &val32);
+ val32 |= HT_LINK_CRCFEN;
+ edac_pci_write_dword(dev, REG_HT_LINK, val32);
+
+ /* Enable SSE reporting etc in Interrupt control reg */
+ edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);
+ val32 |= PCI_INTBRG_CTRL_POLL_MASK;
+ edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);
+ }
+}
+
+static void amd8111_pci_bridge_exit(struct amd8111_pci_info *pci_info)
+{
+ u32 val32;
+ struct pci_dev *dev = pci_info->dev;
+
+ if (edac_op_state == EDAC_OPSTATE_POLL) {
+ /* Disable System Error reporting */
+ edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32);
+ val32 &= ~PCI_STSCMD_SERREN;
+ edac_pci_write_dword(dev, REG_PCI_STSCMD, val32);
+
+ /* Disable CRC flood packets */
+ edac_pci_read_dword(dev, REG_HT_LINK, &val32);
+ val32 &= ~HT_LINK_CRCFEN;
+ edac_pci_write_dword(dev, REG_HT_LINK, val32);
+
+ /* Disable DTSERREN/MARSP/SERREN in Interrupt Control reg */
+ edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);
+ val32 &= ~PCI_INTBRG_CTRL_POLL_MASK;
+ edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);
+ }
+}
+
+static void amd8111_pci_bridge_check(struct edac_pci_ctl_info *edac_dev)
+{
+ struct amd8111_pci_info *pci_info = edac_dev->pvt_info;
+ struct pci_dev *dev = pci_info->dev;
+ u32 val32;
+
+ /* Check out PCI Bridge Status and Command Register */
+ edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32);
+ if (val32 & PCI_STSCMD_CLEAR_MASK) {
+ printk(KERN_INFO "Error(s) in PCI bridge status and command"
+ "register on device %s\n", pci_info->ctl_name);
+ printk(KERN_INFO "SSE: %d, RMA: %d, RTA: %d\n",
+ (val32 & PCI_STSCMD_SSE) != 0,
+ (val32 & PCI_STSCMD_RMA) != 0,
+ (val32 & PCI_STSCMD_RTA) != 0);
+
+ val32 |= PCI_STSCMD_CLEAR_MASK;
+ edac_pci_write_dword(dev, REG_PCI_STSCMD, val32);
+
+ edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+ }
+
+ /* Check out HyperTransport Link Control Register */
+ edac_pci_read_dword(dev, REG_HT_LINK, &val32);
+ if (val32 & HT_LINK_LKFAIL) {
+ printk(KERN_INFO "Error(s) in hypertransport link control"
+ "register on device %s\n", pci_info->ctl_name);
+ printk(KERN_INFO "LKFAIL: %d\n",
+ (val32 & HT_LINK_LKFAIL) != 0);
+
+ val32 |= HT_LINK_LKFAIL;
+ edac_pci_write_dword(dev, REG_HT_LINK, val32);
+
+ edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+ }
+
+ /* Check out PCI Interrupt and Bridge Control Register */
+ edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);
+ if (val32 & PCI_INTBRG_CTRL_DTSTAT) {
+ printk(KERN_INFO "Error(s) in PCI interrupt and bridge control"
+ "register on device %s\n", pci_info->ctl_name);
+ printk(KERN_INFO "DTSTAT: %d\n",
+ (val32 & PCI_INTBRG_CTRL_DTSTAT) != 0);
+
+ val32 |= PCI_INTBRG_CTRL_DTSTAT;
+ edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);
+
+ edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+ }
+
+ /* Check out PCI Bridge Memory Base-Limit Register */
+ edac_pci_read_dword(dev, REG_MEM_LIM, &val32);
+ if (val32 & MEM_LIMIT_CLEAR_MASK) {
+ printk(KERN_INFO
+ "Error(s) in mem limit register on %s device\n",
+ pci_info->ctl_name);
+ printk(KERN_INFO "DPE: %d, RSE: %d, RMA: %d\n"
+ "RTA: %d, STA: %d, MDPE: %d\n",
+ (val32 & MEM_LIMIT_DPE) != 0,
+ (val32 & MEM_LIMIT_RSE) != 0,
+ (val32 & MEM_LIMIT_RMA) != 0,
+ (val32 & MEM_LIMIT_RTA) != 0,
+ (val32 & MEM_LIMIT_STA) != 0,
+ (val32 & MEM_LIMIT_MDPE) != 0);
+
+ val32 |= MEM_LIMIT_CLEAR_MASK;
+ edac_pci_write_dword(dev, REG_MEM_LIM, val32);
+
+ edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+ }
+}
+
+static struct resource *legacy_io_res;
+static int at_compat_reg_broken;
+#define LEGACY_NR_PORTS 1
+
+/* device-specific methods for amd8111 LPC Bridge device */
+static void amd8111_lpc_bridge_init(struct amd8111_dev_info *dev_info)
+{
+ u8 val8;
+ struct pci_dev *dev = dev_info->dev;
+
+ /* First clear REG_AT_COMPAT[SERR, IOCHK] if necessary */
+ legacy_io_res = request_region(REG_AT_COMPAT, LEGACY_NR_PORTS,
+ AMD8111_EDAC_MOD_STR);
+ if (!legacy_io_res)
+ printk(KERN_INFO "%s: failed to request legacy I/O region "
+ "start %d, len %d\n", __func__,
+ REG_AT_COMPAT, LEGACY_NR_PORTS);
+ else {
+ val8 = __do_inb(REG_AT_COMPAT);
+ if (val8 == 0xff) { /* buggy port */
+ printk(KERN_INFO "%s: port %d is buggy, not supported"
+ " by hardware?\n", __func__, REG_AT_COMPAT);
+ at_compat_reg_broken = 1;
+ release_region(REG_AT_COMPAT, LEGACY_NR_PORTS);
+ legacy_io_res = NULL;
+ } else {
+ u8 out8 = 0;
+ if (val8 & AT_COMPAT_SERR)
+ out8 = AT_COMPAT_CLRSERR;
+ if (val8 & AT_COMPAT_IOCHK)
+ out8 |= AT_COMPAT_CLRIOCHK;
+ if (out8 > 0)
+ __do_outb(out8, REG_AT_COMPAT);
+ }
+ }
+
+ /* Second clear error flags on LPC bridge */
+ edac_pci_read_byte(dev, REG_IO_CTRL_1, &val8);
+ if (val8 & IO_CTRL_1_CLEAR_MASK)
+ edac_pci_write_byte(dev, REG_IO_CTRL_1, val8);
+}
+
+static void amd8111_lpc_bridge_exit(struct amd8111_dev_info *dev_info)
+{
+ if (legacy_io_res)
+ release_region(REG_AT_COMPAT, LEGACY_NR_PORTS);
+}
+
+static void amd8111_lpc_bridge_check(struct edac_device_ctl_info *edac_dev)
+{
+ struct amd8111_dev_info *dev_info = edac_dev->pvt_info;
+ struct pci_dev *dev = dev_info->dev;
+ u8 val8;
+
+ edac_pci_read_byte(dev, REG_IO_CTRL_1, &val8);
+ if (val8 & IO_CTRL_1_CLEAR_MASK) {
+ printk(KERN_INFO
+ "Error(s) in IO control register on %s device\n",
+ dev_info->ctl_name);
+ printk(KERN_INFO "LPC ERR: %d, PW2LPC: %d\n",
+ (val8 & IO_CTRL_1_LPC_ERR) != 0,
+ (val8 & IO_CTRL_1_PW2LPC) != 0);
+
+ val8 |= IO_CTRL_1_CLEAR_MASK;
+ edac_pci_write_byte(dev, REG_IO_CTRL_1, val8);
+
+ edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);
+ }
+
+ if (at_compat_reg_broken == 0) {
+ u8 out8 = 0;
+ val8 = __do_inb(REG_AT_COMPAT);
+ if (val8 & AT_COMPAT_SERR)
+ out8 = AT_COMPAT_CLRSERR;
+ if (val8 & AT_COMPAT_IOCHK)
+ out8 |= AT_COMPAT_CLRIOCHK;
+ if (out8 > 0) {
+ __do_outb(out8, REG_AT_COMPAT);
+ edac_device_handle_ue(edac_dev, 0, 0,
+ edac_dev->ctl_name);
+ }
+ }
+}
+
+/* General devices represented by edac_device_ctl_info */
+static struct amd8111_dev_info amd8111_devices[] = {
+ [LPC_BRIDGE] = {
+ .err_dev = PCI_DEVICE_ID_AMD_8111_LPC,
+ .ctl_name = "lpc",
+ .init = amd8111_lpc_bridge_init,
+ .exit = amd8111_lpc_bridge_exit,
+ .check = amd8111_lpc_bridge_check,
+ },
+ {0},
+};
+
+/* PCI controllers represented by edac_pci_ctl_info */
+static struct amd8111_pci_info amd8111_pcis[] = {
+ [PCI_BRIDGE] = {
+ .err_dev = PCI_DEVICE_ID_AMD_8111_PCI,
+ .ctl_name = "AMD8111_PCI_Controller",
+ .init = amd8111_pci_bridge_init,
+ .exit = amd8111_pci_bridge_exit,
+ .check = amd8111_pci_bridge_check,
+ },
+ {0},
+};
+
+static int amd8111_dev_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct amd8111_dev_info *dev_info = &amd8111_devices[id->driver_data];
+
+ dev_info->dev = pci_get_device(PCI_VENDOR_ID_AMD,
+ dev_info->err_dev, NULL);
+
+ if (!dev_info->dev) {
+ printk(KERN_ERR "EDAC device not found:"
+ "vendor %x, device %x, name %s\n",
+ PCI_VENDOR_ID_AMD, dev_info->err_dev,
+ dev_info->ctl_name);
+ return -ENODEV;
+ }
+
+ if (pci_enable_device(dev_info->dev)) {
+ pci_dev_put(dev_info->dev);
+ printk(KERN_ERR "failed to enable:"
+ "vendor %x, device %x, name %s\n",
+ PCI_VENDOR_ID_AMD, dev_info->err_dev,
+ dev_info->ctl_name);
+ return -ENODEV;
+ }
+
+ /*
+ * we do not allocate extra private structure for
+ * edac_device_ctl_info, but make use of existing
+ * one instead.
+ */
+ dev_info->edac_idx = edac_dev_idx++;
+ dev_info->edac_dev =
+ edac_device_alloc_ctl_info(0, dev_info->ctl_name, 1,
+ NULL, 0, 0,
+ NULL, 0, dev_info->edac_idx);
+ if (!dev_info->edac_dev)
+ return -ENOMEM;
+
+ dev_info->edac_dev->pvt_info = dev_info;
+ dev_info->edac_dev->dev = &dev_info->dev->dev;
+ dev_info->edac_dev->mod_name = AMD8111_EDAC_MOD_STR;
+ dev_info->edac_dev->ctl_name = dev_info->ctl_name;
+ dev_info->edac_dev->dev_name = dev_info->dev->dev.bus_id;
+
+ if (edac_op_state == EDAC_OPSTATE_POLL)
+ dev_info->edac_dev->edac_check = dev_info->check;
+
+ if (dev_info->init)
+ dev_info->init(dev_info);
+
+ if (edac_device_add_device(dev_info->edac_dev) > 0) {
+ printk(KERN_ERR "failed to add edac_dev for %s\n",
+ dev_info->ctl_name);
+ edac_device_free_ctl_info(dev_info->edac_dev);
+ return -ENODEV;
+ }
+
+ printk(KERN_INFO "added one edac_dev on AMD8111 "
+ "vendor %x, device %x, name %s\n",
+ PCI_VENDOR_ID_AMD, dev_info->err_dev,
+ dev_info->ctl_name);
+
+ return 0;
+}
+
+static void amd8111_dev_remove(struct pci_dev *dev)
+{
+ struct amd8111_dev_info *dev_info;
+
+ for (dev_info = amd8111_devices; dev_info->err_dev; dev_info++)
+ if (dev_info->dev->device == dev->device)
+ break;
+
+ if (!dev_info->err_dev) /* should never happen */
+ return;
+
+ if (dev_info->edac_dev) {
+ edac_device_del_device(dev_info->edac_dev->dev);
+ edac_device_free_ctl_info(dev_info->edac_dev);
+ }
+
+ if (dev_info->exit)
+ dev_info->exit(dev_info);
+
+ pci_dev_put(dev_info->dev);
+}
+
+static int amd8111_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct amd8111_pci_info *pci_info = &amd8111_pcis[id->driver_data];
+
+ pci_info->dev = pci_get_device(PCI_VENDOR_ID_AMD,
+ pci_info->err_dev, NULL);
+
+ if (!pci_info->dev) {
+ printk(KERN_ERR "EDAC device not found:"
+ "vendor %x, device %x, name %s\n",
+ PCI_VENDOR_ID_AMD, pci_info->err_dev,
+ pci_info->ctl_name);
+ return -ENODEV;
+ }
+
+ if (pci_enable_device(pci_info->dev)) {
+ pci_dev_put(pci_info->dev);
+ printk(KERN_ERR "failed to enable:"
+ "vendor %x, device %x, name %s\n",
+ PCI_VENDOR_ID_AMD, pci_info->err_dev,
+ pci_info->ctl_name);
+ return -ENODEV;
+ }
+
+ /*
+ * we do not allocate extra private structure for
+ * edac_pci_ctl_info, but make use of existing
+ * one instead.
+ */
+ pci_info->edac_idx = edac_pci_alloc_index();
+ pci_info->edac_dev = edac_pci_alloc_ctl_info(0, pci_info->ctl_name);
+ if (!pci_info->edac_dev)
+ return -ENOMEM;
+
+ pci_info->edac_dev->pvt_info = pci_info;
+ pci_info->edac_dev->dev = &pci_info->dev->dev;
+ pci_info->edac_dev->mod_name = AMD8111_EDAC_MOD_STR;
+ pci_info->edac_dev->ctl_name = pci_info->ctl_name;
+ pci_info->edac_dev->dev_name = pci_info->dev->dev.bus_id;
+
+ if (edac_op_state == EDAC_OPSTATE_POLL)
+ pci_info->edac_dev->edac_check = pci_info->check;
+
+ if (pci_info->init)
+ pci_info->init(pci_info);
+
+ if (edac_pci_add_device(pci_info->edac_dev, pci_info->edac_idx) > 0) {
+ printk(KERN_ERR "failed to add edac_pci for %s\n",
+ pci_info->ctl_name);
+ edac_pci_free_ctl_info(pci_info->edac_dev);
+ return -ENODEV;
+ }
+
+ printk(KERN_INFO "added one edac_pci on AMD8111 "
+ "vendor %x, device %x, name %s\n",
+ PCI_VENDOR_ID_AMD, pci_info->err_dev,
+ pci_info->ctl_name);
+
+ return 0;
+}
+
+static void amd8111_pci_remove(struct pci_dev *dev)
+{
+ struct amd8111_pci_info *pci_info;
+
+ for (pci_info = amd8111_pcis; pci_info->err_dev; pci_info++)
+ if (pci_info->dev->device == dev->device)
+ break;
+
+ if (!pci_info->err_dev) /* should never happen */
+ return;
+
+ if (pci_info->edac_dev) {
+ edac_pci_del_device(pci_info->edac_dev->dev);
+ edac_pci_free_ctl_info(pci_info->edac_dev);
+ }
+
+ if (pci_info->exit)
+ pci_info->exit(pci_info);
+
+ pci_dev_put(pci_info->dev);
+}
+
+/* PCI Device ID talbe for general EDAC device */
+static const struct pci_device_id amd8111_edac_dev_tbl[] = {
+ {
+ PCI_VEND_DEV(AMD, 8111_LPC),
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .class = 0,
+ .class_mask = 0,
+ .driver_data = LPC_BRIDGE,
+ },
+ {
+ 0,
+ } /* table is NULL-terminated */
+};
+MODULE_DEVICE_TABLE(pci, amd8111_edac_dev_tbl);
+
+static struct pci_driver amd8111_edac_dev_driver = {
+ .name = "AMD8111_EDAC_DEV",
+ .probe = amd8111_dev_probe,
+ .remove = amd8111_dev_remove,
+ .id_table = amd8111_edac_dev_tbl,
+};
+
+/* PCI Device ID table for EDAC PCI controller */
+static const struct pci_device_id amd8111_edac_pci_tbl[] = {
+ {
+ PCI_VEND_DEV(AMD, 8111_PCI),
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .class = 0,
+ .class_mask = 0,
+ .driver_data = PCI_BRIDGE,
+ },
+ {
+ 0,
+ } /* table is NULL-terminated */
+};
+MODULE_DEVICE_TABLE(pci, amd8111_edac_pci_tbl);
+
+static struct pci_driver amd8111_edac_pci_driver = {
+ .name = "AMD8111_EDAC_PCI",
+ .probe = amd8111_pci_probe,
+ .remove = amd8111_pci_remove,
+ .id_table = amd8111_edac_pci_tbl,
+};
+
+static int __init amd8111_edac_init(void)
+{
+ int val;
+
+ printk(KERN_INFO "AMD8111 EDAC driver " AMD8111_EDAC_REVISION "\n");
+ printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc.\n");
+
+ /* Only POLL mode supported so far */
+ edac_op_state = EDAC_OPSTATE_POLL;
+
+ val = pci_register_driver(&amd8111_edac_dev_driver);
+ val |= pci_register_driver(&amd8111_edac_pci_driver);
+
+ return val;
+}
+
+static void __exit amd8111_edac_exit(void)
+{
+ pci_unregister_driver(&amd8111_edac_pci_driver);
+ pci_unregister_driver(&amd8111_edac_dev_driver);
+}
+
+
+module_init(amd8111_edac_init);
+module_exit(amd8111_edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Cao Qingtao <[email protected]>\n");
+MODULE_DESCRIPTION("AMD8111 HyperTransport I/O Hub EDAC kernel module");
--
1.5.6.2

2009-03-11 03:40:29

by Harry Ciao

[permalink] [raw]
Subject: [v2 PATCH 6/7] EDAC: AMD8131 driver source file

Introduce AMD8131 EDAC driver source file, which makes use of error
detections on the PCI-X Bridge Controllers on the AMD8131 HyperTransport
PCI-X Tunnel.

Signed-off-by: Harry Ciao <[email protected]>
---
drivers/edac/amd8131_edac.c | 379 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 379 insertions(+)
create mode 100644 drivers/edac/amd8131_edac.c

--- /dev/null
+++ b/drivers/edac/amd8131_edac.c
@@ -0,0 +1,379 @@
+/*
+ * amd8131_edac.c, AMD8131 hypertransport chip EDAC kernel module
+ *
+ * Copyright (c) 2008 Wind River Systems, Inc.
+ *
+ * Authors: Cao Qingtao <[email protected]>
+ * Benjamin Walsh <[email protected]>
+ * Hu Yongqi <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/edac.h>
+#include <linux/pci_ids.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+#include "amd8131_edac.h"
+
+#define AMD8131_EDAC_REVISION " Ver: 1.0.0 " __DATE__
+#define AMD8131_EDAC_MOD_STR "amd8131_edac"
+
+/* Wrapper functions for accessing PCI configuration space */
+static void edac_pci_read_dword(struct pci_dev *dev, int reg, u32 *val32)
+{
+ int ret;
+
+ ret = pci_read_config_dword(dev, reg, val32);
+ if (ret != 0)
+ printk(KERN_ERR AMD8131_EDAC_MOD_STR
+ " PCI Access Read Error at 0x%x\n", reg);
+}
+
+static void edac_pci_write_dword(struct pci_dev *dev, int reg, u32 val32)
+{
+ int ret;
+
+ ret = pci_write_config_dword(dev, reg, val32);
+ if (ret != 0)
+ printk(KERN_ERR AMD8131_EDAC_MOD_STR
+ " PCI Access Write Error at 0x%x\n", reg);
+}
+
+static char * const bridge_str[] = {
+ [NORTH_A] = "NORTH A",
+ [NORTH_B] = "NORTH B",
+ [SOUTH_A] = "SOUTH A",
+ [SOUTH_B] = "SOUTH B",
+ [NO_BRIDGE] = "NO BRIDGE",
+};
+
+/* Support up to two AMD8131 chipsets on a platform */
+static struct amd8131_dev_info amd8131_devices[] = {
+ {
+ .inst = NORTH_A,
+ .devfn = DEVFN_PCIX_BRIDGE_NORTH_A,
+ .ctl_name = "AMD8131_PCIX_NORTH_A",
+ },
+ {
+ .inst = NORTH_B,
+ .devfn = DEVFN_PCIX_BRIDGE_NORTH_B,
+ .ctl_name = "AMD8131_PCIX_NORTH_B",
+ },
+ {
+ .inst = SOUTH_A,
+ .devfn = DEVFN_PCIX_BRIDGE_SOUTH_A,
+ .ctl_name = "AMD8131_PCIX_SOUTH_A",
+ },
+ {
+ .inst = SOUTH_B,
+ .devfn = DEVFN_PCIX_BRIDGE_SOUTH_B,
+ .ctl_name = "AMD8131_PCIX_SOUTH_B",
+ },
+ {.inst = NO_BRIDGE,},
+};
+
+static void amd8131_pcix_init(struct amd8131_dev_info *dev_info)
+{
+ u32 val32;
+ struct pci_dev *dev = dev_info->dev;
+
+ /* First clear error detection flags */
+ edac_pci_read_dword(dev, REG_MEM_LIM, &val32);
+ if (val32 & MEM_LIMIT_MASK)
+ edac_pci_write_dword(dev, REG_MEM_LIM, val32);
+
+ /* Clear Discard Timer Timedout flag */
+ edac_pci_read_dword(dev, REG_INT_CTLR, &val32);
+ if (val32 & INT_CTLR_DTS)
+ edac_pci_write_dword(dev, REG_INT_CTLR, val32);
+
+ /* Clear CRC Error flag on link side A */
+ edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32);
+ if (val32 & LNK_CTRL_CRCERR_A)
+ edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32);
+
+ /* Clear CRC Error flag on link side B */
+ edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32);
+ if (val32 & LNK_CTRL_CRCERR_B)
+ edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32);
+
+ /*
+ * Then enable all error detections.
+ *
+ * Setup Discard Timer Sync Flood Enable,
+ * System Error Enable and Parity Error Enable.
+ */
+ edac_pci_read_dword(dev, REG_INT_CTLR, &val32);
+ val32 |= INT_CTLR_PERR | INT_CTLR_SERR | INT_CTLR_DTSE;
+ edac_pci_write_dword(dev, REG_INT_CTLR, val32);
+
+ /* Enable overall SERR Error detection */
+ edac_pci_read_dword(dev, REG_STS_CMD, &val32);
+ val32 |= STS_CMD_SERREN;
+ edac_pci_write_dword(dev, REG_STS_CMD, val32);
+
+ /* Setup CRC Flood Enable for link side A */
+ edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32);
+ val32 |= LNK_CTRL_CRCFEN;
+ edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32);
+
+ /* Setup CRC Flood Enable for link side B */
+ edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32);
+ val32 |= LNK_CTRL_CRCFEN;
+ edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32);
+}
+
+static void amd8131_pcix_exit(struct amd8131_dev_info *dev_info)
+{
+ u32 val32;
+ struct pci_dev *dev = dev_info->dev;
+
+ /* Disable SERR, PERR and DTSE Error detection */
+ edac_pci_read_dword(dev, REG_INT_CTLR, &val32);
+ val32 &= ~(INT_CTLR_PERR | INT_CTLR_SERR | INT_CTLR_DTSE);
+ edac_pci_write_dword(dev, REG_INT_CTLR, val32);
+
+ /* Disable overall System Error detection */
+ edac_pci_read_dword(dev, REG_STS_CMD, &val32);
+ val32 &= ~STS_CMD_SERREN;
+ edac_pci_write_dword(dev, REG_STS_CMD, val32);
+
+ /* Disable CRC Sync Flood on link side A */
+ edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32);
+ val32 &= ~LNK_CTRL_CRCFEN;
+ edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32);
+
+ /* Disable CRC Sync Flood on link side B */
+ edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32);
+ val32 &= ~LNK_CTRL_CRCFEN;
+ edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32);
+}
+
+static void amd8131_pcix_check(struct edac_pci_ctl_info *edac_dev)
+{
+ struct amd8131_dev_info *dev_info = edac_dev->pvt_info;
+ struct pci_dev *dev = dev_info->dev;
+ u32 val32;
+
+ /* Check PCI-X Bridge Memory Base-Limit Register for errors */
+ edac_pci_read_dword(dev, REG_MEM_LIM, &val32);
+ if (val32 & MEM_LIMIT_MASK) {
+ printk(KERN_INFO "Error(s) in mem limit register "
+ "on %s bridge\n", dev_info->ctl_name);
+ printk(KERN_INFO "DPE: %d, RSE: %d, RMA: %d\n"
+ "RTA: %d, STA: %d, MDPE: %d\n",
+ val32 & MEM_LIMIT_DPE,
+ val32 & MEM_LIMIT_RSE,
+ val32 & MEM_LIMIT_RMA,
+ val32 & MEM_LIMIT_RTA,
+ val32 & MEM_LIMIT_STA,
+ val32 & MEM_LIMIT_MDPE);
+
+ val32 |= MEM_LIMIT_MASK;
+ edac_pci_write_dword(dev, REG_MEM_LIM, val32);
+
+ edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+ }
+
+ /* Check if Discard Timer timed out */
+ edac_pci_read_dword(dev, REG_INT_CTLR, &val32);
+ if (val32 & INT_CTLR_DTS) {
+ printk(KERN_INFO "Error(s) in interrupt and control register "
+ "on %s bridge\n", dev_info->ctl_name);
+ printk(KERN_INFO "DTS: %d\n", val32 & INT_CTLR_DTS);
+
+ val32 |= INT_CTLR_DTS;
+ edac_pci_write_dword(dev, REG_INT_CTLR, val32);
+
+ edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+ }
+
+ /* Check if CRC error happens on link side A */
+ edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32);
+ if (val32 & LNK_CTRL_CRCERR_A) {
+ printk(KERN_INFO "Error(s) in link conf and control register "
+ "on %s bridge\n", dev_info->ctl_name);
+ printk(KERN_INFO "CRCERR: %d\n", val32 & LNK_CTRL_CRCERR_A);
+
+ val32 |= LNK_CTRL_CRCERR_A;
+ edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32);
+
+ edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+ }
+
+ /* Check if CRC error happens on link side B */
+ edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32);
+ if (val32 & LNK_CTRL_CRCERR_B) {
+ printk(KERN_INFO "Error(s) in link conf and control register "
+ "on %s bridge\n", dev_info->ctl_name);
+ printk(KERN_INFO "CRCERR: %d\n", val32 & LNK_CTRL_CRCERR_B);
+
+ val32 |= LNK_CTRL_CRCERR_B;
+ edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32);
+
+ edac_pci_handle_npe(edac_dev, edac_dev->ctl_name);
+ }
+}
+
+static struct amd8131_info amd8131_chipset = {
+ .err_dev = PCI_DEVICE_ID_AMD_8131_APIC,
+ .devices = amd8131_devices,
+ .init = amd8131_pcix_init,
+ .exit = amd8131_pcix_exit,
+ .check = amd8131_pcix_check,
+};
+
+/*
+ * There are 4 PCIX Bridges on ATCA-6101 that share the same PCI Device ID,
+ * so amd8131_probe() would be called by kernel 4 times, with different
+ * address of pci_dev for each of them each time.
+ */
+static int amd8131_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct amd8131_dev_info *dev_info;
+
+ for (dev_info = amd8131_chipset.devices; dev_info->inst != NO_BRIDGE;
+ dev_info++)
+ if (dev_info->devfn == dev->devfn)
+ break;
+
+ if (dev_info->inst == NO_BRIDGE) /* should never happen */
+ return -ENODEV;
+
+ /*
+ * We can't call pci_get_device() as we are used to do because
+ * there are 4 of them but pci_dev_get() instead.
+ */
+ dev_info->dev = pci_dev_get(dev);
+
+ if (pci_enable_device(dev_info->dev)) {
+ pci_dev_put(dev_info->dev);
+ printk(KERN_ERR "failed to enable:"
+ "vendor %x, device %x, devfn %x, name %s\n",
+ PCI_VENDOR_ID_AMD, amd8131_chipset.err_dev,
+ dev_info->devfn, dev_info->ctl_name);
+ return -ENODEV;
+ }
+
+ /*
+ * we do not allocate extra private structure for
+ * edac_pci_ctl_info, but make use of existing
+ * one instead.
+ */
+ dev_info->edac_idx = edac_pci_alloc_index();
+ dev_info->edac_dev = edac_pci_alloc_ctl_info(0, dev_info->ctl_name);
+ if (!dev_info->edac_dev)
+ return -ENOMEM;
+
+ dev_info->edac_dev->pvt_info = dev_info;
+ dev_info->edac_dev->dev = &dev_info->dev->dev;
+ dev_info->edac_dev->mod_name = AMD8131_EDAC_MOD_STR;
+ dev_info->edac_dev->ctl_name = dev_info->ctl_name;
+ dev_info->edac_dev->dev_name = dev_info->dev->dev.bus_id;
+
+ if (edac_op_state == EDAC_OPSTATE_POLL)
+ dev_info->edac_dev->edac_check = amd8131_chipset.check;
+
+ if (amd8131_chipset.init)
+ amd8131_chipset.init(dev_info);
+
+ if (edac_pci_add_device(dev_info->edac_dev, dev_info->edac_idx) > 0) {
+ printk(KERN_ERR "failed edac_pci_add_device() for %s\n",
+ dev_info->ctl_name);
+ edac_pci_free_ctl_info(dev_info->edac_dev);
+ return -ENODEV;
+ }
+
+ printk(KERN_INFO "added one device on AMD8131 "
+ "vendor %x, device %x, devfn %x, name %s\n",
+ PCI_VENDOR_ID_AMD, amd8131_chipset.err_dev,
+ dev_info->devfn, dev_info->ctl_name);
+
+ return 0;
+}
+
+static void amd8131_remove(struct pci_dev *dev)
+{
+ struct amd8131_dev_info *dev_info;
+
+ for (dev_info = amd8131_chipset.devices; dev_info->inst != NO_BRIDGE;
+ dev_info++)
+ if (dev_info->devfn == dev->devfn)
+ break;
+
+ if (dev_info->inst == NO_BRIDGE) /* should never happen */
+ return;
+
+ if (dev_info->edac_dev) {
+ edac_pci_del_device(dev_info->edac_dev->dev);
+ edac_pci_free_ctl_info(dev_info->edac_dev);
+ }
+
+ if (amd8131_chipset.exit)
+ amd8131_chipset.exit(dev_info);
+
+ pci_dev_put(dev_info->dev);
+}
+
+static const struct pci_device_id amd8131_edac_pci_tbl[] = {
+ {
+ PCI_VEND_DEV(AMD, 8131_BRIDGE),
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .class = 0,
+ .class_mask = 0,
+ .driver_data = 0,
+ },
+ {
+ 0,
+ } /* table is NULL-terminated */
+};
+MODULE_DEVICE_TABLE(pci, amd8131_edac_pci_tbl);
+
+static struct pci_driver amd8131_edac_driver = {
+ .name = AMD8131_EDAC_MOD_STR,
+ .probe = amd8131_probe,
+ .remove = amd8131_remove,
+ .id_table = amd8131_edac_pci_tbl,
+};
+
+static int __init amd8131_edac_init(void)
+{
+ printk(KERN_INFO "AMD8131 EDAC driver " AMD8131_EDAC_REVISION "\n");
+ printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc.\n");
+
+ /* Only POLL mode supported so far */
+ edac_op_state = EDAC_OPSTATE_POLL;
+
+ return pci_register_driver(&amd8131_edac_driver);
+}
+
+static void __exit amd8131_edac_exit(void)
+{
+ pci_unregister_driver(&amd8131_edac_driver);
+}
+
+module_init(amd8131_edac_init);
+module_exit(amd8131_edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Cao Qingtao <[email protected]>\n");
+MODULE_DESCRIPTION("AMD8131 HyperTransport PCI-X Tunnel EDAC kernel module");

2009-03-11 03:41:09

by Harry Ciao

[permalink] [raw]
Subject: [v2 PATCH 7/7] EDAC: AMD8131 driver Kconfig and Makefile

Introduce Kconfig and Makefile options for AMD8131 EDAC driver.

Signed-off-by: Harry Ciao <[email protected]>
---
drivers/edac/Kconfig | 7 +++++++
drivers/edac/Makefile | 1 +
2 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 46f8e77..13ccec6 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -181,4 +181,11 @@ config EDAC_AMD8111
Support for error detection and correction on the
AMD8111 HyperTransport I/O Hub chip.

+config EDAC_AMD8131
+ tristate "AMD8131 HyperTransport PCI-X Tunnel"
+ depends on EDAC_MM_EDAC && PCI
+ help
+ Support for error detection and correction on the
+ AMD8131 HyperTransport PCI-X Tunnel chip.
+
endif # EDAC
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index c324956..407601f 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -35,4 +35,5 @@ obj-$(CONFIG_EDAC_MPC85XX) += mpc85xx_edac.o
obj-$(CONFIG_EDAC_MV64X60) += mv64x60_edac.o
obj-$(CONFIG_EDAC_CELL) += cell_edac.o
obj-$(CONFIG_EDAC_AMD8111) += amd8111_edac.o
+obj-$(CONFIG_EDAC_AMD8131) += amd8131_edac.o

--
1.5.6.2

2009-03-11 19:14:18

by Doug Thompson

[permalink] [raw]
Subject: Re: [v2 PATCH 0/7] Add AMD8111 and AMD8131 EDAC drivers


--- On Tue, 3/10/09, Harry Ciao <[email protected]> wrote:

> From: Harry Ciao <[email protected]>
> Subject: [v2 PATCH 0/7] Add AMD8111 and AMD8131 EDAC drivers
> To: [email protected], [email protected]
> Date: Tuesday, March 10, 2009, 9:25 PM
>
> Hi,
>
> This is the v2 series of patches for EDAC AMD8111 &
> AMD8131 drivers.
> I have integrated suggestions from Bert, Greg and Andrew.
> Tests all passed on Maple platform, these modules could be
> properly
> loaded/unloaded, with their sysfs interfaces
> created/cleaned.
>
> Any suggestions are warmly welcomed!
>
> Best regards,
>
> Harry
>
>
> Comments:??? ???
> ---------
> Introduce AMD8111 EDAC driver, which makes use of error
> detections
> on the LPC Bridge Controller and PCI Bridge Controller on
> the AMD8111
> HyperTransport I/O Hub.
>
> Introduce AMD8131 EDAC driver source file, which makes use
> of error
> detections on the PCI-X Bridge Controllers on the AMD8131
> HyperTransport
> PCI-X Tunnel.
>
> Since both AMD8111 and AMD8131 EDAC drivers would use
> edac_pci_ctl_info
> structures, EDAC core has to take the responsibility to
> allocate a unique
> "edac_pci_idx" for each of them, by newly added
> edac_pci_alloc_index().
>
> Note, by far only POLL mode is supported, and they have
> been tested on
> MAPLE platform, from below test logs we can tell that they
> could be
> correctly installed and removed, and export proper sysfs
> interfaces.

harry,

thanks for the new edac_pci_alloc_index(). I have been meaning to solve that issue for sometime, but didn't have a pressing need to do so. You brought one and solved it.

thanks again

doug t