diff options
Diffstat (limited to 'drivers/edac')
-rw-r--r-- | drivers/edac/Kconfig | 3 | ||||
-rw-r--r-- | drivers/edac/Makefile | 1 | ||||
-rw-r--r-- | drivers/edac/edac_mce.c | 61 | ||||
-rw-r--r-- | drivers/edac/i7core_edac.c | 51 |
4 files changed, 25 insertions, 91 deletions
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index af1a17d42bd7..f888fb599184 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig | |||
@@ -71,9 +71,6 @@ config EDAC_MM_EDAC | |||
71 | occurred so that a particular failing memory module can be | 71 | occurred so that a particular failing memory module can be |
72 | replaced. If unsure, select 'Y'. | 72 | replaced. If unsure, select 'Y'. |
73 | 73 | ||
74 | config EDAC_MCE | ||
75 | bool | ||
76 | |||
77 | config EDAC_AMD64 | 74 | config EDAC_AMD64 |
78 | tristate "AMD64 (Opteron, Athlon64) K8, F10h" | 75 | tristate "AMD64 (Opteron, Athlon64) K8, F10h" |
79 | depends on EDAC_MM_EDAC && AMD_NB && X86_64 && EDAC_DECODE_MCE | 76 | depends on EDAC_MM_EDAC && AMD_NB && X86_64 && EDAC_DECODE_MCE |
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index 3e239133e29e..b06a9b11a5f6 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile | |||
@@ -8,7 +8,6 @@ | |||
8 | 8 | ||
9 | obj-$(CONFIG_EDAC) := edac_stub.o | 9 | obj-$(CONFIG_EDAC) := edac_stub.o |
10 | obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o | 10 | obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o |
11 | obj-$(CONFIG_EDAC_MCE) += edac_mce.o | ||
12 | 11 | ||
13 | edac_core-y := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o | 12 | edac_core-y := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o |
14 | edac_core-y += edac_module.o edac_device_sysfs.o | 13 | edac_core-y += edac_module.o edac_device_sysfs.o |
diff --git a/drivers/edac/edac_mce.c b/drivers/edac/edac_mce.c deleted file mode 100644 index 9ccdc5b140e7..000000000000 --- a/drivers/edac/edac_mce.c +++ /dev/null | |||
@@ -1,61 +0,0 @@ | |||
1 | /* Provides edac interface to mcelog events | ||
2 | * | ||
3 | * This file may be distributed under the terms of the | ||
4 | * GNU General Public License version 2. | ||
5 | * | ||
6 | * Copyright (c) 2009 by: | ||
7 | * Mauro Carvalho Chehab <mchehab@redhat.com> | ||
8 | * | ||
9 | * Red Hat Inc. http://www.redhat.com | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/edac_mce.h> | ||
14 | #include <asm/mce.h> | ||
15 | |||
16 | int edac_mce_enabled; | ||
17 | EXPORT_SYMBOL_GPL(edac_mce_enabled); | ||
18 | |||
19 | |||
20 | /* | ||
21 | * Extension interface | ||
22 | */ | ||
23 | |||
24 | static LIST_HEAD(edac_mce_list); | ||
25 | static DEFINE_MUTEX(edac_mce_lock); | ||
26 | |||
27 | int edac_mce_register(struct edac_mce *edac_mce) | ||
28 | { | ||
29 | mutex_lock(&edac_mce_lock); | ||
30 | list_add_tail(&edac_mce->list, &edac_mce_list); | ||
31 | mutex_unlock(&edac_mce_lock); | ||
32 | return 0; | ||
33 | } | ||
34 | EXPORT_SYMBOL(edac_mce_register); | ||
35 | |||
36 | void edac_mce_unregister(struct edac_mce *edac_mce) | ||
37 | { | ||
38 | mutex_lock(&edac_mce_lock); | ||
39 | list_del(&edac_mce->list); | ||
40 | mutex_unlock(&edac_mce_lock); | ||
41 | } | ||
42 | EXPORT_SYMBOL(edac_mce_unregister); | ||
43 | |||
44 | int edac_mce_parse(struct mce *mce) | ||
45 | { | ||
46 | struct edac_mce *edac_mce; | ||
47 | |||
48 | list_for_each_entry(edac_mce, &edac_mce_list, list) { | ||
49 | if (edac_mce->check_error(edac_mce->priv, mce)) | ||
50 | return 1; | ||
51 | } | ||
52 | |||
53 | /* Nobody queued the error */ | ||
54 | return 0; | ||
55 | } | ||
56 | EXPORT_SYMBOL_GPL(edac_mce_parse); | ||
57 | |||
58 | MODULE_LICENSE("GPL"); | ||
59 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); | ||
60 | MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); | ||
61 | MODULE_DESCRIPTION("EDAC Driver for mcelog captured errors"); | ||
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 764207ed6d44..0bddc27362c1 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c | |||
@@ -33,8 +33,8 @@ | |||
33 | #include <linux/delay.h> | 33 | #include <linux/delay.h> |
34 | #include <linux/edac.h> | 34 | #include <linux/edac.h> |
35 | #include <linux/mmzone.h> | 35 | #include <linux/mmzone.h> |
36 | #include <linux/edac_mce.h> | ||
37 | #include <linux/smp.h> | 36 | #include <linux/smp.h> |
37 | #include <asm/mce.h> | ||
38 | #include <asm/processor.h> | 38 | #include <asm/processor.h> |
39 | 39 | ||
40 | #include "edac_core.h" | 40 | #include "edac_core.h" |
@@ -265,9 +265,6 @@ struct i7core_pvt { | |||
265 | 265 | ||
266 | bool is_registered, enable_scrub; | 266 | bool is_registered, enable_scrub; |
267 | 267 | ||
268 | /* mcelog glue */ | ||
269 | struct edac_mce edac_mce; | ||
270 | |||
271 | /* Fifo double buffers */ | 268 | /* Fifo double buffers */ |
272 | struct mce mce_entry[MCE_LOG_LEN]; | 269 | struct mce mce_entry[MCE_LOG_LEN]; |
273 | struct mce mce_outentry[MCE_LOG_LEN]; | 270 | struct mce mce_outentry[MCE_LOG_LEN]; |
@@ -1899,33 +1896,43 @@ check_ce_error: | |||
1899 | * WARNING: As this routine should be called at NMI time, extra care should | 1896 | * WARNING: As this routine should be called at NMI time, extra care should |
1900 | * be taken to avoid deadlocks, and to be as fast as possible. | 1897 | * be taken to avoid deadlocks, and to be as fast as possible. |
1901 | */ | 1898 | */ |
1902 | static int i7core_mce_check_error(void *priv, struct mce *mce) | 1899 | static int i7core_mce_check_error(struct notifier_block *nb, unsigned long val, |
1900 | void *data) | ||
1903 | { | 1901 | { |
1904 | struct mem_ctl_info *mci = priv; | 1902 | struct mce *mce = (struct mce *)data; |
1905 | struct i7core_pvt *pvt = mci->pvt_info; | 1903 | struct i7core_dev *i7_dev; |
1904 | struct mem_ctl_info *mci; | ||
1905 | struct i7core_pvt *pvt; | ||
1906 | |||
1907 | i7_dev = get_i7core_dev(mce->socketid); | ||
1908 | if (!i7_dev) | ||
1909 | return NOTIFY_BAD; | ||
1910 | |||
1911 | mci = i7_dev->mci; | ||
1912 | pvt = mci->pvt_info; | ||
1906 | 1913 | ||
1907 | /* | 1914 | /* |
1908 | * Just let mcelog handle it if the error is | 1915 | * Just let mcelog handle it if the error is |
1909 | * outside the memory controller | 1916 | * outside the memory controller |
1910 | */ | 1917 | */ |
1911 | if (((mce->status & 0xffff) >> 7) != 1) | 1918 | if (((mce->status & 0xffff) >> 7) != 1) |
1912 | return 0; | 1919 | return NOTIFY_DONE; |
1913 | 1920 | ||
1914 | /* Bank 8 registers are the only ones that we know how to handle */ | 1921 | /* Bank 8 registers are the only ones that we know how to handle */ |
1915 | if (mce->bank != 8) | 1922 | if (mce->bank != 8) |
1916 | return 0; | 1923 | return NOTIFY_DONE; |
1917 | 1924 | ||
1918 | #ifdef CONFIG_SMP | 1925 | #ifdef CONFIG_SMP |
1919 | /* Only handle if it is the right mc controller */ | 1926 | /* Only handle if it is the right mc controller */ |
1920 | if (mce->socketid != pvt->i7core_dev->socket) | 1927 | if (mce->socketid != pvt->i7core_dev->socket) |
1921 | return 0; | 1928 | return NOTIFY_DONE; |
1922 | #endif | 1929 | #endif |
1923 | 1930 | ||
1924 | smp_rmb(); | 1931 | smp_rmb(); |
1925 | if ((pvt->mce_out + 1) % MCE_LOG_LEN == pvt->mce_in) { | 1932 | if ((pvt->mce_out + 1) % MCE_LOG_LEN == pvt->mce_in) { |
1926 | smp_wmb(); | 1933 | smp_wmb(); |
1927 | pvt->mce_overrun++; | 1934 | pvt->mce_overrun++; |
1928 | return 0; | 1935 | return NOTIFY_DONE; |
1929 | } | 1936 | } |
1930 | 1937 | ||
1931 | /* Copy memory error at the ringbuffer */ | 1938 | /* Copy memory error at the ringbuffer */ |
@@ -1938,9 +1945,13 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) | |||
1938 | i7core_check_error(mci); | 1945 | i7core_check_error(mci); |
1939 | 1946 | ||
1940 | /* Advise mcelog that the errors were handled */ | 1947 | /* Advise mcelog that the errors were handled */ |
1941 | return 1; | 1948 | return NOTIFY_STOP; |
1942 | } | 1949 | } |
1943 | 1950 | ||
1951 | static struct notifier_block i7_mce_dec = { | ||
1952 | .notifier_call = i7core_mce_check_error, | ||
1953 | }; | ||
1954 | |||
1944 | /* | 1955 | /* |
1945 | * set_sdram_scrub_rate This routine sets byte/sec bandwidth scrub rate | 1956 | * set_sdram_scrub_rate This routine sets byte/sec bandwidth scrub rate |
1946 | * to hardware according to SCRUBINTERVAL formula | 1957 | * to hardware according to SCRUBINTERVAL formula |
@@ -2093,8 +2104,7 @@ static void i7core_unregister_mci(struct i7core_dev *i7core_dev) | |||
2093 | if (pvt->enable_scrub) | 2104 | if (pvt->enable_scrub) |
2094 | disable_sdram_scrub_setting(mci); | 2105 | disable_sdram_scrub_setting(mci); |
2095 | 2106 | ||
2096 | /* Disable MCE NMI handler */ | 2107 | atomic_notifier_chain_unregister(&x86_mce_decoder_chain, &i7_mce_dec); |
2097 | edac_mce_unregister(&pvt->edac_mce); | ||
2098 | 2108 | ||
2099 | /* Disable EDAC polling */ | 2109 | /* Disable EDAC polling */ |
2100 | i7core_pci_ctl_release(pvt); | 2110 | i7core_pci_ctl_release(pvt); |
@@ -2193,21 +2203,10 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev) | |||
2193 | /* allocating generic PCI control info */ | 2203 | /* allocating generic PCI control info */ |
2194 | i7core_pci_ctl_create(pvt); | 2204 | i7core_pci_ctl_create(pvt); |
2195 | 2205 | ||
2196 | /* Registers on edac_mce in order to receive memory errors */ | 2206 | atomic_notifier_chain_register(&x86_mce_decoder_chain, &i7_mce_dec); |
2197 | pvt->edac_mce.priv = mci; | ||
2198 | pvt->edac_mce.check_error = i7core_mce_check_error; | ||
2199 | rc = edac_mce_register(&pvt->edac_mce); | ||
2200 | if (unlikely(rc < 0)) { | ||
2201 | debugf0("MC: " __FILE__ | ||
2202 | ": %s(): failed edac_mce_register()\n", __func__); | ||
2203 | goto fail1; | ||
2204 | } | ||
2205 | 2207 | ||
2206 | return 0; | 2208 | return 0; |
2207 | 2209 | ||
2208 | fail1: | ||
2209 | i7core_pci_ctl_release(pvt); | ||
2210 | edac_mc_del_mc(mci->dev); | ||
2211 | fail0: | 2210 | fail0: |
2212 | kfree(mci->ctl_name); | 2211 | kfree(mci->ctl_name); |
2213 | edac_mc_free(mci); | 2212 | edac_mc_free(mci); |