diff options
-rw-r--r-- | Documentation/edac.txt | 10 | ||||
-rw-r--r-- | MAINTAINERS | 23 | ||||
-rw-r--r-- | arch/powerpc/sysdev/fsl_pci.c | 28 | ||||
-rw-r--r-- | arch/powerpc/sysdev/fsl_pci.h | 9 | ||||
-rw-r--r-- | drivers/edac/Makefile | 2 | ||||
-rw-r--r-- | drivers/edac/edac_device.c | 41 | ||||
-rw-r--r-- | drivers/edac/edac_device_sysfs.c | 11 | ||||
-rw-r--r-- | drivers/edac/edac_mc.c | 29 | ||||
-rw-r--r-- | drivers/edac/edac_mc_sysfs.c | 37 | ||||
-rw-r--r-- | drivers/edac/edac_module.c | 52 | ||||
-rw-r--r-- | drivers/edac/edac_module.h | 10 | ||||
-rw-r--r-- | drivers/edac/edac_pci.c | 70 | ||||
-rw-r--r-- | drivers/edac/edac_pci_sysfs.c | 16 | ||||
-rw-r--r-- | drivers/edac/edac_stub.c | 41 | ||||
-rw-r--r-- | drivers/edac/i5100_edac.c | 4 | ||||
-rw-r--r-- | drivers/edac/mpc85xx_edac.c | 54 | ||||
-rw-r--r-- | drivers/edac/mv64x60_edac.c | 39 | ||||
-rw-r--r-- | drivers/edac/sb_edac.c | 1071 | ||||
-rw-r--r-- | drivers/edac/wq.c | 42 | ||||
-rw-r--r-- | include/linux/edac.h | 8 | ||||
-rw-r--r-- | include/linux/fsl/edac.h | 8 |
21 files changed, 1236 insertions, 369 deletions
diff --git a/Documentation/edac.txt b/Documentation/edac.txt index 80841a2d640c..f89cfd85ae13 100644 --- a/Documentation/edac.txt +++ b/Documentation/edac.txt | |||
@@ -1,9 +1,13 @@ | |||
1 | EDAC - Error Detection And Correction | 1 | EDAC - Error Detection And Correction |
2 | ===================================== | 2 | ===================================== |
3 | 3 | ||
4 | "bluesmoke" was the name for this device driver when it was "out-of-tree" | 4 | "bluesmoke" was the name for this device driver when it |
5 | and maintained at sourceforge.net. When it was pushed into 2.6.16 for the | 5 | was "out-of-tree" and maintained at sourceforge.net - |
6 | first time, it was renamed to 'EDAC'. | 6 | bluesmoke.sourceforge.net. That site is mostly archaic now and can be |
7 | used only for historical purposes. | ||
8 | |||
9 | When the subsystem was pushed into 2.6.16 for the first time, it was | ||
10 | renamed to 'EDAC'. | ||
7 | 11 | ||
8 | PURPOSE | 12 | PURPOSE |
9 | ------- | 13 | ------- |
diff --git a/MAINTAINERS b/MAINTAINERS index cbfb81b5ced5..ab8695d6e75c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -3933,9 +3933,8 @@ M: Doug Thompson <dougthompson@xmission.com> | |||
3933 | M: Borislav Petkov <bp@alien8.de> | 3933 | M: Borislav Petkov <bp@alien8.de> |
3934 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 3934 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
3935 | L: linux-edac@vger.kernel.org | 3935 | L: linux-edac@vger.kernel.org |
3936 | W: bluesmoke.sourceforge.net | 3936 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git for-next |
3937 | T: git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git#for-next | 3937 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac.git linux_next |
3938 | T: git://git.kernel.org/pub/linux/kernel/git/mchehab/linux-edac.git#linux_next | ||
3939 | S: Supported | 3938 | S: Supported |
3940 | F: Documentation/edac.txt | 3939 | F: Documentation/edac.txt |
3941 | F: drivers/edac/ | 3940 | F: drivers/edac/ |
@@ -3945,7 +3944,6 @@ EDAC-AMD64 | |||
3945 | M: Doug Thompson <dougthompson@xmission.com> | 3944 | M: Doug Thompson <dougthompson@xmission.com> |
3946 | M: Borislav Petkov <bp@alien8.de> | 3945 | M: Borislav Petkov <bp@alien8.de> |
3947 | L: linux-edac@vger.kernel.org | 3946 | L: linux-edac@vger.kernel.org |
3948 | W: bluesmoke.sourceforge.net | ||
3949 | S: Maintained | 3947 | S: Maintained |
3950 | F: drivers/edac/amd64_edac* | 3948 | F: drivers/edac/amd64_edac* |
3951 | 3949 | ||
@@ -3953,7 +3951,6 @@ EDAC-CALXEDA | |||
3953 | M: Doug Thompson <dougthompson@xmission.com> | 3951 | M: Doug Thompson <dougthompson@xmission.com> |
3954 | M: Robert Richter <rric@kernel.org> | 3952 | M: Robert Richter <rric@kernel.org> |
3955 | L: linux-edac@vger.kernel.org | 3953 | L: linux-edac@vger.kernel.org |
3956 | W: bluesmoke.sourceforge.net | ||
3957 | S: Maintained | 3954 | S: Maintained |
3958 | F: drivers/edac/highbank* | 3955 | F: drivers/edac/highbank* |
3959 | 3956 | ||
@@ -3962,7 +3959,6 @@ M: Ralf Baechle <ralf@linux-mips.org> | |||
3962 | M: David Daney <david.daney@cavium.com> | 3959 | M: David Daney <david.daney@cavium.com> |
3963 | L: linux-edac@vger.kernel.org | 3960 | L: linux-edac@vger.kernel.org |
3964 | L: linux-mips@linux-mips.org | 3961 | L: linux-mips@linux-mips.org |
3965 | W: bluesmoke.sourceforge.net | ||
3966 | S: Supported | 3962 | S: Supported |
3967 | F: drivers/edac/octeon_edac* | 3963 | F: drivers/edac/octeon_edac* |
3968 | 3964 | ||
@@ -3970,63 +3966,54 @@ EDAC-E752X | |||
3970 | M: Mark Gross <mark.gross@intel.com> | 3966 | M: Mark Gross <mark.gross@intel.com> |
3971 | M: Doug Thompson <dougthompson@xmission.com> | 3967 | M: Doug Thompson <dougthompson@xmission.com> |
3972 | L: linux-edac@vger.kernel.org | 3968 | L: linux-edac@vger.kernel.org |
3973 | W: bluesmoke.sourceforge.net | ||
3974 | S: Maintained | 3969 | S: Maintained |
3975 | F: drivers/edac/e752x_edac.c | 3970 | F: drivers/edac/e752x_edac.c |
3976 | 3971 | ||
3977 | EDAC-E7XXX | 3972 | EDAC-E7XXX |
3978 | M: Doug Thompson <dougthompson@xmission.com> | 3973 | M: Doug Thompson <dougthompson@xmission.com> |
3979 | L: linux-edac@vger.kernel.org | 3974 | L: linux-edac@vger.kernel.org |
3980 | W: bluesmoke.sourceforge.net | ||
3981 | S: Maintained | 3975 | S: Maintained |
3982 | F: drivers/edac/e7xxx_edac.c | 3976 | F: drivers/edac/e7xxx_edac.c |
3983 | 3977 | ||
3984 | EDAC-GHES | 3978 | EDAC-GHES |
3985 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 3979 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
3986 | L: linux-edac@vger.kernel.org | 3980 | L: linux-edac@vger.kernel.org |
3987 | W: bluesmoke.sourceforge.net | ||
3988 | S: Maintained | 3981 | S: Maintained |
3989 | F: drivers/edac/ghes_edac.c | 3982 | F: drivers/edac/ghes_edac.c |
3990 | 3983 | ||
3991 | EDAC-I82443BXGX | 3984 | EDAC-I82443BXGX |
3992 | M: Tim Small <tim@buttersideup.com> | 3985 | M: Tim Small <tim@buttersideup.com> |
3993 | L: linux-edac@vger.kernel.org | 3986 | L: linux-edac@vger.kernel.org |
3994 | W: bluesmoke.sourceforge.net | ||
3995 | S: Maintained | 3987 | S: Maintained |
3996 | F: drivers/edac/i82443bxgx_edac.c | 3988 | F: drivers/edac/i82443bxgx_edac.c |
3997 | 3989 | ||
3998 | EDAC-I3000 | 3990 | EDAC-I3000 |
3999 | M: Jason Uhlenkott <juhlenko@akamai.com> | 3991 | M: Jason Uhlenkott <juhlenko@akamai.com> |
4000 | L: linux-edac@vger.kernel.org | 3992 | L: linux-edac@vger.kernel.org |
4001 | W: bluesmoke.sourceforge.net | ||
4002 | S: Maintained | 3993 | S: Maintained |
4003 | F: drivers/edac/i3000_edac.c | 3994 | F: drivers/edac/i3000_edac.c |
4004 | 3995 | ||
4005 | EDAC-I5000 | 3996 | EDAC-I5000 |
4006 | M: Doug Thompson <dougthompson@xmission.com> | 3997 | M: Doug Thompson <dougthompson@xmission.com> |
4007 | L: linux-edac@vger.kernel.org | 3998 | L: linux-edac@vger.kernel.org |
4008 | W: bluesmoke.sourceforge.net | ||
4009 | S: Maintained | 3999 | S: Maintained |
4010 | F: drivers/edac/i5000_edac.c | 4000 | F: drivers/edac/i5000_edac.c |
4011 | 4001 | ||
4012 | EDAC-I5400 | 4002 | EDAC-I5400 |
4013 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 4003 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
4014 | L: linux-edac@vger.kernel.org | 4004 | L: linux-edac@vger.kernel.org |
4015 | W: bluesmoke.sourceforge.net | ||
4016 | S: Maintained | 4005 | S: Maintained |
4017 | F: drivers/edac/i5400_edac.c | 4006 | F: drivers/edac/i5400_edac.c |
4018 | 4007 | ||
4019 | EDAC-I7300 | 4008 | EDAC-I7300 |
4020 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 4009 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
4021 | L: linux-edac@vger.kernel.org | 4010 | L: linux-edac@vger.kernel.org |
4022 | W: bluesmoke.sourceforge.net | ||
4023 | S: Maintained | 4011 | S: Maintained |
4024 | F: drivers/edac/i7300_edac.c | 4012 | F: drivers/edac/i7300_edac.c |
4025 | 4013 | ||
4026 | EDAC-I7CORE | 4014 | EDAC-I7CORE |
4027 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 4015 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
4028 | L: linux-edac@vger.kernel.org | 4016 | L: linux-edac@vger.kernel.org |
4029 | W: bluesmoke.sourceforge.net | ||
4030 | S: Maintained | 4017 | S: Maintained |
4031 | F: drivers/edac/i7core_edac.c | 4018 | F: drivers/edac/i7core_edac.c |
4032 | 4019 | ||
@@ -4034,42 +4021,36 @@ EDAC-I82975X | |||
4034 | M: Ranganathan Desikan <ravi@jetztechnologies.com> | 4021 | M: Ranganathan Desikan <ravi@jetztechnologies.com> |
4035 | M: "Arvind R." <arvino55@gmail.com> | 4022 | M: "Arvind R." <arvino55@gmail.com> |
4036 | L: linux-edac@vger.kernel.org | 4023 | L: linux-edac@vger.kernel.org |
4037 | W: bluesmoke.sourceforge.net | ||
4038 | S: Maintained | 4024 | S: Maintained |
4039 | F: drivers/edac/i82975x_edac.c | 4025 | F: drivers/edac/i82975x_edac.c |
4040 | 4026 | ||
4041 | EDAC-IE31200 | 4027 | EDAC-IE31200 |
4042 | M: Jason Baron <jbaron@akamai.com> | 4028 | M: Jason Baron <jbaron@akamai.com> |
4043 | L: linux-edac@vger.kernel.org | 4029 | L: linux-edac@vger.kernel.org |
4044 | W: bluesmoke.sourceforge.net | ||
4045 | S: Maintained | 4030 | S: Maintained |
4046 | F: drivers/edac/ie31200_edac.c | 4031 | F: drivers/edac/ie31200_edac.c |
4047 | 4032 | ||
4048 | EDAC-MPC85XX | 4033 | EDAC-MPC85XX |
4049 | M: Johannes Thumshirn <morbidrsa@gmail.com> | 4034 | M: Johannes Thumshirn <morbidrsa@gmail.com> |
4050 | L: linux-edac@vger.kernel.org | 4035 | L: linux-edac@vger.kernel.org |
4051 | W: bluesmoke.sourceforge.net | ||
4052 | S: Maintained | 4036 | S: Maintained |
4053 | F: drivers/edac/mpc85xx_edac.[ch] | 4037 | F: drivers/edac/mpc85xx_edac.[ch] |
4054 | 4038 | ||
4055 | EDAC-PASEMI | 4039 | EDAC-PASEMI |
4056 | M: Egor Martovetsky <egor@pasemi.com> | 4040 | M: Egor Martovetsky <egor@pasemi.com> |
4057 | L: linux-edac@vger.kernel.org | 4041 | L: linux-edac@vger.kernel.org |
4058 | W: bluesmoke.sourceforge.net | ||
4059 | S: Maintained | 4042 | S: Maintained |
4060 | F: drivers/edac/pasemi_edac.c | 4043 | F: drivers/edac/pasemi_edac.c |
4061 | 4044 | ||
4062 | EDAC-R82600 | 4045 | EDAC-R82600 |
4063 | M: Tim Small <tim@buttersideup.com> | 4046 | M: Tim Small <tim@buttersideup.com> |
4064 | L: linux-edac@vger.kernel.org | 4047 | L: linux-edac@vger.kernel.org |
4065 | W: bluesmoke.sourceforge.net | ||
4066 | S: Maintained | 4048 | S: Maintained |
4067 | F: drivers/edac/r82600_edac.c | 4049 | F: drivers/edac/r82600_edac.c |
4068 | 4050 | ||
4069 | EDAC-SBRIDGE | 4051 | EDAC-SBRIDGE |
4070 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 4052 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
4071 | L: linux-edac@vger.kernel.org | 4053 | L: linux-edac@vger.kernel.org |
4072 | W: bluesmoke.sourceforge.net | ||
4073 | S: Maintained | 4054 | S: Maintained |
4074 | F: drivers/edac/sb_edac.c | 4055 | F: drivers/edac/sb_edac.c |
4075 | 4056 | ||
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 610f472f91d1..a1ac80b3041a 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c | |||
@@ -21,10 +21,12 @@ | |||
21 | #include <linux/pci.h> | 21 | #include <linux/pci.h> |
22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/string.h> | 23 | #include <linux/string.h> |
24 | #include <linux/fsl/edac.h> | ||
24 | #include <linux/init.h> | 25 | #include <linux/init.h> |
25 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
26 | #include <linux/memblock.h> | 27 | #include <linux/memblock.h> |
27 | #include <linux/log2.h> | 28 | #include <linux/log2.h> |
29 | #include <linux/platform_device.h> | ||
28 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
29 | #include <linux/suspend.h> | 31 | #include <linux/suspend.h> |
30 | #include <linux/syscore_ops.h> | 32 | #include <linux/syscore_ops.h> |
@@ -1255,6 +1257,25 @@ void fsl_pcibios_fixup_phb(struct pci_controller *phb) | |||
1255 | #endif | 1257 | #endif |
1256 | } | 1258 | } |
1257 | 1259 | ||
1260 | static int add_err_dev(struct platform_device *pdev) | ||
1261 | { | ||
1262 | struct platform_device *errdev; | ||
1263 | struct mpc85xx_edac_pci_plat_data pd = { | ||
1264 | .of_node = pdev->dev.of_node | ||
1265 | }; | ||
1266 | |||
1267 | errdev = platform_device_register_resndata(&pdev->dev, | ||
1268 | "mpc85xx-pci-edac", | ||
1269 | PLATFORM_DEVID_AUTO, | ||
1270 | pdev->resource, | ||
1271 | pdev->num_resources, | ||
1272 | &pd, sizeof(pd)); | ||
1273 | if (IS_ERR(errdev)) | ||
1274 | return PTR_ERR(errdev); | ||
1275 | |||
1276 | return 0; | ||
1277 | } | ||
1278 | |||
1258 | static int fsl_pci_probe(struct platform_device *pdev) | 1279 | static int fsl_pci_probe(struct platform_device *pdev) |
1259 | { | 1280 | { |
1260 | struct device_node *node; | 1281 | struct device_node *node; |
@@ -1262,8 +1283,13 @@ static int fsl_pci_probe(struct platform_device *pdev) | |||
1262 | 1283 | ||
1263 | node = pdev->dev.of_node; | 1284 | node = pdev->dev.of_node; |
1264 | ret = fsl_add_bridge(pdev, fsl_pci_primary == node); | 1285 | ret = fsl_add_bridge(pdev, fsl_pci_primary == node); |
1286 | if (ret) | ||
1287 | return ret; | ||
1265 | 1288 | ||
1266 | mpc85xx_pci_err_probe(pdev); | 1289 | ret = add_err_dev(pdev); |
1290 | if (ret) | ||
1291 | dev_err(&pdev->dev, "couldn't register error device: %d\n", | ||
1292 | ret); | ||
1267 | 1293 | ||
1268 | return 0; | 1294 | return 0; |
1269 | } | 1295 | } |
diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.h index c1cec771d5ea..151588530b06 100644 --- a/arch/powerpc/sysdev/fsl_pci.h +++ b/arch/powerpc/sysdev/fsl_pci.h | |||
@@ -130,15 +130,6 @@ void fsl_pci_assign_primary(void); | |||
130 | static inline void fsl_pci_assign_primary(void) {} | 130 | static inline void fsl_pci_assign_primary(void) {} |
131 | #endif | 131 | #endif |
132 | 132 | ||
133 | #ifdef CONFIG_EDAC_MPC85XX | ||
134 | int mpc85xx_pci_err_probe(struct platform_device *op); | ||
135 | #else | ||
136 | static inline int mpc85xx_pci_err_probe(struct platform_device *op) | ||
137 | { | ||
138 | return -ENOTSUPP; | ||
139 | } | ||
140 | #endif | ||
141 | |||
142 | #ifdef CONFIG_FSL_PCI | 133 | #ifdef CONFIG_FSL_PCI |
143 | extern int fsl_pci_mcheck_exception(struct pt_regs *); | 134 | extern int fsl_pci_mcheck_exception(struct pt_regs *); |
144 | #else | 135 | #else |
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index dbf53e08bdd1..be163e20fe56 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile | |||
@@ -10,7 +10,7 @@ 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 | 11 | ||
12 | edac_core-y := edac_mc.o edac_device.o edac_mc_sysfs.o | 12 | edac_core-y := edac_mc.o edac_device.o edac_mc_sysfs.o |
13 | edac_core-y += edac_module.o edac_device_sysfs.o | 13 | edac_core-y += edac_module.o edac_device_sysfs.o wq.o |
14 | 14 | ||
15 | edac_core-$(CONFIG_EDAC_DEBUG) += debugfs.o | 15 | edac_core-$(CONFIG_EDAC_DEBUG) += debugfs.o |
16 | 16 | ||
diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c index 592af5f0cf39..a97900333e2d 100644 --- a/drivers/edac/edac_device.c +++ b/drivers/edac/edac_device.c | |||
@@ -390,11 +390,9 @@ static void edac_device_workq_function(struct work_struct *work_req) | |||
390 | * between integral seconds | 390 | * between integral seconds |
391 | */ | 391 | */ |
392 | if (edac_dev->poll_msec == 1000) | 392 | if (edac_dev->poll_msec == 1000) |
393 | queue_delayed_work(edac_workqueue, &edac_dev->work, | 393 | edac_queue_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay)); |
394 | round_jiffies_relative(edac_dev->delay)); | ||
395 | else | 394 | else |
396 | queue_delayed_work(edac_workqueue, &edac_dev->work, | 395 | edac_queue_work(&edac_dev->work, edac_dev->delay); |
397 | edac_dev->delay); | ||
398 | } | 396 | } |
399 | 397 | ||
400 | /* | 398 | /* |
@@ -402,8 +400,8 @@ static void edac_device_workq_function(struct work_struct *work_req) | |||
402 | * initialize a workq item for this edac_device instance | 400 | * initialize a workq item for this edac_device instance |
403 | * passing in the new delay period in msec | 401 | * passing in the new delay period in msec |
404 | */ | 402 | */ |
405 | void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev, | 403 | static void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev, |
406 | unsigned msec) | 404 | unsigned msec) |
407 | { | 405 | { |
408 | edac_dbg(0, "\n"); | 406 | edac_dbg(0, "\n"); |
409 | 407 | ||
@@ -422,29 +420,23 @@ void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev, | |||
422 | * to fire together on the 1 second exactly | 420 | * to fire together on the 1 second exactly |
423 | */ | 421 | */ |
424 | if (edac_dev->poll_msec == 1000) | 422 | if (edac_dev->poll_msec == 1000) |
425 | queue_delayed_work(edac_workqueue, &edac_dev->work, | 423 | edac_queue_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay)); |
426 | round_jiffies_relative(edac_dev->delay)); | ||
427 | else | 424 | else |
428 | queue_delayed_work(edac_workqueue, &edac_dev->work, | 425 | edac_queue_work(&edac_dev->work, edac_dev->delay); |
429 | edac_dev->delay); | ||
430 | } | 426 | } |
431 | 427 | ||
432 | /* | 428 | /* |
433 | * edac_device_workq_teardown | 429 | * edac_device_workq_teardown |
434 | * stop the workq processing on this edac_dev | 430 | * stop the workq processing on this edac_dev |
435 | */ | 431 | */ |
436 | void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev) | 432 | static void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev) |
437 | { | 433 | { |
438 | int status; | ||
439 | |||
440 | if (!edac_dev->edac_check) | 434 | if (!edac_dev->edac_check) |
441 | return; | 435 | return; |
442 | 436 | ||
443 | status = cancel_delayed_work(&edac_dev->work); | 437 | edac_dev->op_state = OP_OFFLINE; |
444 | if (status == 0) { | 438 | |
445 | /* workq instance might be running, wait for it */ | 439 | edac_stop_work(&edac_dev->work); |
446 | flush_workqueue(edac_workqueue); | ||
447 | } | ||
448 | } | 440 | } |
449 | 441 | ||
450 | /* | 442 | /* |
@@ -457,16 +449,15 @@ void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev) | |||
457 | void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev, | 449 | void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev, |
458 | unsigned long value) | 450 | unsigned long value) |
459 | { | 451 | { |
460 | /* cancel the current workq request, without the mutex lock */ | 452 | unsigned long jiffs = msecs_to_jiffies(value); |
461 | edac_device_workq_teardown(edac_dev); | ||
462 | 453 | ||
463 | /* acquire the mutex before doing the workq setup */ | 454 | if (value == 1000) |
464 | mutex_lock(&device_ctls_mutex); | 455 | jiffs = round_jiffies_relative(value); |
465 | 456 | ||
466 | /* restart the workq request, with new delay value */ | 457 | edac_dev->poll_msec = value; |
467 | edac_device_workq_setup(edac_dev, value); | 458 | edac_dev->delay = jiffs; |
468 | 459 | ||
469 | mutex_unlock(&device_ctls_mutex); | 460 | edac_mod_work(&edac_dev->work, jiffs); |
470 | } | 461 | } |
471 | 462 | ||
472 | /* | 463 | /* |
diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c index fb68a06ad683..93da1a45c716 100644 --- a/drivers/edac/edac_device_sysfs.c +++ b/drivers/edac/edac_device_sysfs.c | |||
@@ -237,11 +237,6 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) | |||
237 | 237 | ||
238 | /* get the /sys/devices/system/edac reference */ | 238 | /* get the /sys/devices/system/edac reference */ |
239 | edac_subsys = edac_get_sysfs_subsys(); | 239 | edac_subsys = edac_get_sysfs_subsys(); |
240 | if (edac_subsys == NULL) { | ||
241 | edac_dbg(1, "no edac_subsys error\n"); | ||
242 | err = -ENODEV; | ||
243 | goto err_out; | ||
244 | } | ||
245 | 240 | ||
246 | /* Point to the 'edac_subsys' this instance 'reports' to */ | 241 | /* Point to the 'edac_subsys' this instance 'reports' to */ |
247 | edac_dev->edac_subsys = edac_subsys; | 242 | edac_dev->edac_subsys = edac_subsys; |
@@ -256,7 +251,7 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) | |||
256 | 251 | ||
257 | if (!try_module_get(edac_dev->owner)) { | 252 | if (!try_module_get(edac_dev->owner)) { |
258 | err = -ENODEV; | 253 | err = -ENODEV; |
259 | goto err_mod_get; | 254 | goto err_out; |
260 | } | 255 | } |
261 | 256 | ||
262 | /* register */ | 257 | /* register */ |
@@ -282,9 +277,6 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) | |||
282 | err_kobj_reg: | 277 | err_kobj_reg: |
283 | module_put(edac_dev->owner); | 278 | module_put(edac_dev->owner); |
284 | 279 | ||
285 | err_mod_get: | ||
286 | edac_put_sysfs_subsys(); | ||
287 | |||
288 | err_out: | 280 | err_out: |
289 | return err; | 281 | return err; |
290 | } | 282 | } |
@@ -306,7 +298,6 @@ void edac_device_unregister_sysfs_main_kobj(struct edac_device_ctl_info *dev) | |||
306 | * b) 'kfree' the memory | 298 | * b) 'kfree' the memory |
307 | */ | 299 | */ |
308 | kobject_put(&dev->kobj); | 300 | kobject_put(&dev->kobj); |
309 | edac_put_sysfs_subsys(); | ||
310 | } | 301 | } |
311 | 302 | ||
312 | /* edac_dev -> instance information */ | 303 | /* edac_dev -> instance information */ |
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 77ecd6a4179a..8adfc167c2e3 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c | |||
@@ -548,8 +548,7 @@ static void edac_mc_workq_function(struct work_struct *work_req) | |||
548 | mutex_unlock(&mem_ctls_mutex); | 548 | mutex_unlock(&mem_ctls_mutex); |
549 | 549 | ||
550 | /* Reschedule */ | 550 | /* Reschedule */ |
551 | queue_delayed_work(edac_workqueue, &mci->work, | 551 | edac_queue_work(&mci->work, msecs_to_jiffies(edac_mc_get_poll_msec())); |
552 | msecs_to_jiffies(edac_mc_get_poll_msec())); | ||
553 | } | 552 | } |
554 | 553 | ||
555 | /* | 554 | /* |
@@ -561,8 +560,7 @@ static void edac_mc_workq_function(struct work_struct *work_req) | |||
561 | * | 560 | * |
562 | * called with the mem_ctls_mutex held | 561 | * called with the mem_ctls_mutex held |
563 | */ | 562 | */ |
564 | static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec, | 563 | static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec) |
565 | bool init) | ||
566 | { | 564 | { |
567 | edac_dbg(0, "\n"); | 565 | edac_dbg(0, "\n"); |
568 | 566 | ||
@@ -570,10 +568,9 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec, | |||
570 | if (mci->op_state != OP_RUNNING_POLL) | 568 | if (mci->op_state != OP_RUNNING_POLL) |
571 | return; | 569 | return; |
572 | 570 | ||
573 | if (init) | 571 | INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function); |
574 | INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function); | ||
575 | 572 | ||
576 | mod_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec)); | 573 | edac_queue_work(&mci->work, msecs_to_jiffies(msec)); |
577 | } | 574 | } |
578 | 575 | ||
579 | /* | 576 | /* |
@@ -586,18 +583,9 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec, | |||
586 | */ | 583 | */ |
587 | static void edac_mc_workq_teardown(struct mem_ctl_info *mci) | 584 | static void edac_mc_workq_teardown(struct mem_ctl_info *mci) |
588 | { | 585 | { |
589 | int status; | 586 | mci->op_state = OP_OFFLINE; |
590 | |||
591 | if (mci->op_state != OP_RUNNING_POLL) | ||
592 | return; | ||
593 | |||
594 | status = cancel_delayed_work(&mci->work); | ||
595 | if (status == 0) { | ||
596 | edac_dbg(0, "not canceled, flush the queue\n"); | ||
597 | 587 | ||
598 | /* workq instance might be running, wait for it */ | 588 | edac_stop_work(&mci->work); |
599 | flush_workqueue(edac_workqueue); | ||
600 | } | ||
601 | } | 589 | } |
602 | 590 | ||
603 | /* | 591 | /* |
@@ -616,9 +604,8 @@ void edac_mc_reset_delay_period(unsigned long value) | |||
616 | list_for_each(item, &mc_devices) { | 604 | list_for_each(item, &mc_devices) { |
617 | mci = list_entry(item, struct mem_ctl_info, link); | 605 | mci = list_entry(item, struct mem_ctl_info, link); |
618 | 606 | ||
619 | edac_mc_workq_setup(mci, value, false); | 607 | edac_mod_work(&mci->work, value); |
620 | } | 608 | } |
621 | |||
622 | mutex_unlock(&mem_ctls_mutex); | 609 | mutex_unlock(&mem_ctls_mutex); |
623 | } | 610 | } |
624 | 611 | ||
@@ -789,7 +776,7 @@ int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci, | |||
789 | /* This instance is NOW RUNNING */ | 776 | /* This instance is NOW RUNNING */ |
790 | mci->op_state = OP_RUNNING_POLL; | 777 | mci->op_state = OP_RUNNING_POLL; |
791 | 778 | ||
792 | edac_mc_workq_setup(mci, edac_mc_get_poll_msec(), true); | 779 | edac_mc_workq_setup(mci, edac_mc_get_poll_msec()); |
793 | } else { | 780 | } else { |
794 | mci->op_state = OP_RUNNING_INTERRUPT; | 781 | mci->op_state = OP_RUNNING_INTERRUPT; |
795 | } | 782 | } |
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index a75acea0f674..26e65ab5932a 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c | |||
@@ -880,21 +880,26 @@ static struct device_type mci_attr_type = { | |||
880 | int edac_create_sysfs_mci_device(struct mem_ctl_info *mci, | 880 | int edac_create_sysfs_mci_device(struct mem_ctl_info *mci, |
881 | const struct attribute_group **groups) | 881 | const struct attribute_group **groups) |
882 | { | 882 | { |
883 | char *name; | ||
883 | int i, err; | 884 | int i, err; |
884 | 885 | ||
885 | /* | 886 | /* |
886 | * The memory controller needs its own bus, in order to avoid | 887 | * The memory controller needs its own bus, in order to avoid |
887 | * namespace conflicts at /sys/bus/edac. | 888 | * namespace conflicts at /sys/bus/edac. |
888 | */ | 889 | */ |
889 | mci->bus->name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx); | 890 | name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx); |
890 | if (!mci->bus->name) | 891 | if (!name) |
891 | return -ENOMEM; | 892 | return -ENOMEM; |
892 | 893 | ||
894 | mci->bus->name = name; | ||
895 | |||
893 | edac_dbg(0, "creating bus %s\n", mci->bus->name); | 896 | edac_dbg(0, "creating bus %s\n", mci->bus->name); |
894 | 897 | ||
895 | err = bus_register(mci->bus); | 898 | err = bus_register(mci->bus); |
896 | if (err < 0) | 899 | if (err < 0) { |
897 | goto fail_free_name; | 900 | kfree(name); |
901 | return err; | ||
902 | } | ||
898 | 903 | ||
899 | /* get the /sys/devices/system/edac subsys reference */ | 904 | /* get the /sys/devices/system/edac subsys reference */ |
900 | mci->dev.type = &mci_attr_type; | 905 | mci->dev.type = &mci_attr_type; |
@@ -961,8 +966,8 @@ fail_unregister_dimm: | |||
961 | device_unregister(&mci->dev); | 966 | device_unregister(&mci->dev); |
962 | fail_unregister_bus: | 967 | fail_unregister_bus: |
963 | bus_unregister(mci->bus); | 968 | bus_unregister(mci->bus); |
964 | fail_free_name: | 969 | kfree(name); |
965 | kfree(mci->bus->name); | 970 | |
966 | return err; | 971 | return err; |
967 | } | 972 | } |
968 | 973 | ||
@@ -993,10 +998,12 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) | |||
993 | 998 | ||
994 | void edac_unregister_sysfs(struct mem_ctl_info *mci) | 999 | void edac_unregister_sysfs(struct mem_ctl_info *mci) |
995 | { | 1000 | { |
1001 | const char *name = mci->bus->name; | ||
1002 | |||
996 | edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev)); | 1003 | edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev)); |
997 | device_unregister(&mci->dev); | 1004 | device_unregister(&mci->dev); |
998 | bus_unregister(mci->bus); | 1005 | bus_unregister(mci->bus); |
999 | kfree(mci->bus->name); | 1006 | kfree(name); |
1000 | } | 1007 | } |
1001 | 1008 | ||
1002 | static void mc_attr_release(struct device *dev) | 1009 | static void mc_attr_release(struct device *dev) |
@@ -1018,24 +1025,15 @@ static struct device_type mc_attr_type = { | |||
1018 | */ | 1025 | */ |
1019 | int __init edac_mc_sysfs_init(void) | 1026 | int __init edac_mc_sysfs_init(void) |
1020 | { | 1027 | { |
1021 | struct bus_type *edac_subsys; | ||
1022 | int err; | 1028 | int err; |
1023 | 1029 | ||
1024 | /* get the /sys/devices/system/edac subsys reference */ | ||
1025 | edac_subsys = edac_get_sysfs_subsys(); | ||
1026 | if (edac_subsys == NULL) { | ||
1027 | edac_dbg(1, "no edac_subsys\n"); | ||
1028 | err = -EINVAL; | ||
1029 | goto out; | ||
1030 | } | ||
1031 | |||
1032 | mci_pdev = kzalloc(sizeof(*mci_pdev), GFP_KERNEL); | 1030 | mci_pdev = kzalloc(sizeof(*mci_pdev), GFP_KERNEL); |
1033 | if (!mci_pdev) { | 1031 | if (!mci_pdev) { |
1034 | err = -ENOMEM; | 1032 | err = -ENOMEM; |
1035 | goto out_put_sysfs; | 1033 | goto out; |
1036 | } | 1034 | } |
1037 | 1035 | ||
1038 | mci_pdev->bus = edac_subsys; | 1036 | mci_pdev->bus = edac_get_sysfs_subsys(); |
1039 | mci_pdev->type = &mc_attr_type; | 1037 | mci_pdev->type = &mc_attr_type; |
1040 | device_initialize(mci_pdev); | 1038 | device_initialize(mci_pdev); |
1041 | dev_set_name(mci_pdev, "mc"); | 1039 | dev_set_name(mci_pdev, "mc"); |
@@ -1050,8 +1048,6 @@ int __init edac_mc_sysfs_init(void) | |||
1050 | 1048 | ||
1051 | out_dev_free: | 1049 | out_dev_free: |
1052 | kfree(mci_pdev); | 1050 | kfree(mci_pdev); |
1053 | out_put_sysfs: | ||
1054 | edac_put_sysfs_subsys(); | ||
1055 | out: | 1051 | out: |
1056 | return err; | 1052 | return err; |
1057 | } | 1053 | } |
@@ -1059,5 +1055,4 @@ int __init edac_mc_sysfs_init(void) | |||
1059 | void edac_mc_sysfs_exit(void) | 1055 | void edac_mc_sysfs_exit(void) |
1060 | { | 1056 | { |
1061 | device_unregister(mci_pdev); | 1057 | device_unregister(mci_pdev); |
1062 | edac_put_sysfs_subsys(); | ||
1063 | } | 1058 | } |
diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c index 9cb082a19d8a..5f8543be995a 100644 --- a/drivers/edac/edac_module.c +++ b/drivers/edac/edac_module.c | |||
@@ -43,9 +43,6 @@ module_param_call(edac_debug_level, edac_set_debug_level, param_get_int, | |||
43 | MODULE_PARM_DESC(edac_debug_level, "EDAC debug level: [0-4], default: 2"); | 43 | MODULE_PARM_DESC(edac_debug_level, "EDAC debug level: [0-4], default: 2"); |
44 | #endif | 44 | #endif |
45 | 45 | ||
46 | /* scope is to module level only */ | ||
47 | struct workqueue_struct *edac_workqueue; | ||
48 | |||
49 | /* | 46 | /* |
50 | * edac_op_state_to_string() | 47 | * edac_op_state_to_string() |
51 | */ | 48 | */ |
@@ -66,31 +63,37 @@ char *edac_op_state_to_string(int opstate) | |||
66 | } | 63 | } |
67 | 64 | ||
68 | /* | 65 | /* |
69 | * edac_workqueue_setup | 66 | * sysfs object: /sys/devices/system/edac |
70 | * initialize the edac work queue for polling operations | 67 | * need to export to other files |
71 | */ | 68 | */ |
72 | static int edac_workqueue_setup(void) | 69 | static struct bus_type edac_subsys = { |
70 | .name = "edac", | ||
71 | .dev_name = "edac", | ||
72 | }; | ||
73 | |||
74 | static int edac_subsys_init(void) | ||
73 | { | 75 | { |
74 | edac_workqueue = create_singlethread_workqueue("edac-poller"); | 76 | int err; |
75 | if (edac_workqueue == NULL) | 77 | |
76 | return -ENODEV; | 78 | /* create the /sys/devices/system/edac directory */ |
77 | else | 79 | err = subsys_system_register(&edac_subsys, NULL); |
78 | return 0; | 80 | if (err) |
81 | printk(KERN_ERR "Error registering toplevel EDAC sysfs dir\n"); | ||
82 | |||
83 | return err; | ||
79 | } | 84 | } |
80 | 85 | ||
81 | /* | 86 | static void edac_subsys_exit(void) |
82 | * edac_workqueue_teardown | ||
83 | * teardown the edac workqueue | ||
84 | */ | ||
85 | static void edac_workqueue_teardown(void) | ||
86 | { | 87 | { |
87 | if (edac_workqueue) { | 88 | bus_unregister(&edac_subsys); |
88 | flush_workqueue(edac_workqueue); | ||
89 | destroy_workqueue(edac_workqueue); | ||
90 | edac_workqueue = NULL; | ||
91 | } | ||
92 | } | 89 | } |
93 | 90 | ||
91 | /* return pointer to the 'edac' node in sysfs */ | ||
92 | struct bus_type *edac_get_sysfs_subsys(void) | ||
93 | { | ||
94 | return &edac_subsys; | ||
95 | } | ||
96 | EXPORT_SYMBOL_GPL(edac_get_sysfs_subsys); | ||
94 | /* | 97 | /* |
95 | * edac_init | 98 | * edac_init |
96 | * module initialization entry point | 99 | * module initialization entry point |
@@ -101,6 +104,10 @@ static int __init edac_init(void) | |||
101 | 104 | ||
102 | edac_printk(KERN_INFO, EDAC_MC, EDAC_VERSION "\n"); | 105 | edac_printk(KERN_INFO, EDAC_MC, EDAC_VERSION "\n"); |
103 | 106 | ||
107 | err = edac_subsys_init(); | ||
108 | if (err) | ||
109 | return err; | ||
110 | |||
104 | /* | 111 | /* |
105 | * Harvest and clear any boot/initialization PCI parity errors | 112 | * Harvest and clear any boot/initialization PCI parity errors |
106 | * | 113 | * |
@@ -129,6 +136,8 @@ err_wq: | |||
129 | edac_mc_sysfs_exit(); | 136 | edac_mc_sysfs_exit(); |
130 | 137 | ||
131 | err_sysfs: | 138 | err_sysfs: |
139 | edac_subsys_exit(); | ||
140 | |||
132 | return err; | 141 | return err; |
133 | } | 142 | } |
134 | 143 | ||
@@ -144,6 +153,7 @@ static void __exit edac_exit(void) | |||
144 | edac_workqueue_teardown(); | 153 | edac_workqueue_teardown(); |
145 | edac_mc_sysfs_exit(); | 154 | edac_mc_sysfs_exit(); |
146 | edac_debugfs_exit(); | 155 | edac_debugfs_exit(); |
156 | edac_subsys_exit(); | ||
147 | } | 157 | } |
148 | 158 | ||
149 | /* | 159 | /* |
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h index b95a48fc723d..cfaacb99c973 100644 --- a/drivers/edac/edac_module.h +++ b/drivers/edac/edac_module.h | |||
@@ -47,10 +47,12 @@ extern int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev); | |||
47 | extern void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev); | 47 | extern void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev); |
48 | 48 | ||
49 | /* edac core workqueue: single CPU mode */ | 49 | /* edac core workqueue: single CPU mode */ |
50 | extern struct workqueue_struct *edac_workqueue; | 50 | int edac_workqueue_setup(void); |
51 | extern void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev, | 51 | void edac_workqueue_teardown(void); |
52 | unsigned msec); | 52 | bool edac_queue_work(struct delayed_work *work, unsigned long delay); |
53 | extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev); | 53 | bool edac_stop_work(struct delayed_work *work); |
54 | bool edac_mod_work(struct delayed_work *work, unsigned long delay); | ||
55 | |||
54 | extern void edac_device_reset_delay_period(struct edac_device_ctl_info | 56 | extern void edac_device_reset_delay_period(struct edac_device_ctl_info |
55 | *edac_dev, unsigned long value); | 57 | *edac_dev, unsigned long value); |
56 | extern void edac_mc_reset_delay_period(unsigned long value); | 58 | extern void edac_mc_reset_delay_period(unsigned long value); |
diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c index 2cf44b4db80c..99685388d3fb 100644 --- a/drivers/edac/edac_pci.c +++ b/drivers/edac/edac_pci.c | |||
@@ -178,41 +178,6 @@ static void del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci) | |||
178 | INIT_LIST_HEAD(&pci->link); | 178 | INIT_LIST_HEAD(&pci->link); |
179 | } | 179 | } |
180 | 180 | ||
181 | #if 0 | ||
182 | /* Older code, but might use in the future */ | ||
183 | |||
184 | /* | ||
185 | * edac_pci_find() | ||
186 | * Search for an edac_pci_ctl_info structure whose index is 'idx' | ||
187 | * | ||
188 | * If found, return a pointer to the structure | ||
189 | * Else return NULL. | ||
190 | * | ||
191 | * Caller must hold pci_ctls_mutex. | ||
192 | */ | ||
193 | struct edac_pci_ctl_info *edac_pci_find(int idx) | ||
194 | { | ||
195 | struct list_head *item; | ||
196 | struct edac_pci_ctl_info *pci; | ||
197 | |||
198 | /* Iterage over list, looking for exact match of ID */ | ||
199 | list_for_each(item, &edac_pci_list) { | ||
200 | pci = list_entry(item, struct edac_pci_ctl_info, link); | ||
201 | |||
202 | if (pci->pci_idx >= idx) { | ||
203 | if (pci->pci_idx == idx) | ||
204 | return pci; | ||
205 | |||
206 | /* not on list, so terminate early */ | ||
207 | break; | ||
208 | } | ||
209 | } | ||
210 | |||
211 | return NULL; | ||
212 | } | ||
213 | EXPORT_SYMBOL_GPL(edac_pci_find); | ||
214 | #endif | ||
215 | |||
216 | /* | 181 | /* |
217 | * edac_pci_workq_function() | 182 | * edac_pci_workq_function() |
218 | * | 183 | * |
@@ -244,7 +209,7 @@ static void edac_pci_workq_function(struct work_struct *work_req) | |||
244 | delay = msecs_to_jiffies(msec); | 209 | delay = msecs_to_jiffies(msec); |
245 | 210 | ||
246 | /* Reschedule only if we are in POLL mode */ | 211 | /* Reschedule only if we are in POLL mode */ |
247 | queue_delayed_work(edac_workqueue, &pci->work, delay); | 212 | edac_queue_work(&pci->work, delay); |
248 | } | 213 | } |
249 | 214 | ||
250 | mutex_unlock(&edac_pci_ctls_mutex); | 215 | mutex_unlock(&edac_pci_ctls_mutex); |
@@ -264,8 +229,8 @@ static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci, | |||
264 | edac_dbg(0, "\n"); | 229 | edac_dbg(0, "\n"); |
265 | 230 | ||
266 | INIT_DELAYED_WORK(&pci->work, edac_pci_workq_function); | 231 | INIT_DELAYED_WORK(&pci->work, edac_pci_workq_function); |
267 | queue_delayed_work(edac_workqueue, &pci->work, | 232 | |
268 | msecs_to_jiffies(edac_pci_get_poll_msec())); | 233 | edac_queue_work(&pci->work, msecs_to_jiffies(edac_pci_get_poll_msec())); |
269 | } | 234 | } |
270 | 235 | ||
271 | /* | 236 | /* |
@@ -274,37 +239,12 @@ static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci, | |||
274 | */ | 239 | */ |
275 | static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci) | 240 | static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci) |
276 | { | 241 | { |
277 | int status; | ||
278 | |||
279 | edac_dbg(0, "\n"); | ||
280 | |||
281 | status = cancel_delayed_work(&pci->work); | ||
282 | if (status == 0) | ||
283 | flush_workqueue(edac_workqueue); | ||
284 | } | ||
285 | |||
286 | /* | ||
287 | * edac_pci_reset_delay_period | ||
288 | * | ||
289 | * called with a new period value for the workq period | ||
290 | * a) stop current workq timer | ||
291 | * b) restart workq timer with new value | ||
292 | */ | ||
293 | void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci, | ||
294 | unsigned long value) | ||
295 | { | ||
296 | edac_dbg(0, "\n"); | 242 | edac_dbg(0, "\n"); |
297 | 243 | ||
298 | edac_pci_workq_teardown(pci); | 244 | pci->op_state = OP_OFFLINE; |
299 | |||
300 | /* need to lock for the setup */ | ||
301 | mutex_lock(&edac_pci_ctls_mutex); | ||
302 | |||
303 | edac_pci_workq_setup(pci, value); | ||
304 | 245 | ||
305 | mutex_unlock(&edac_pci_ctls_mutex); | 246 | edac_stop_work(&pci->work); |
306 | } | 247 | } |
307 | EXPORT_SYMBOL_GPL(edac_pci_reset_delay_period); | ||
308 | 248 | ||
309 | /* | 249 | /* |
310 | * edac_pci_alloc_index: Allocate a unique PCI index number | 250 | * edac_pci_alloc_index: Allocate a unique PCI index number |
diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c index 24d877f6e577..6e3428ba400f 100644 --- a/drivers/edac/edac_pci_sysfs.c +++ b/drivers/edac/edac_pci_sysfs.c | |||
@@ -331,10 +331,7 @@ static struct kobj_type ktype_edac_pci_main_kobj = { | |||
331 | }; | 331 | }; |
332 | 332 | ||
333 | /** | 333 | /** |
334 | * edac_pci_main_kobj_setup() | 334 | * edac_pci_main_kobj_setup: Setup the sysfs for EDAC PCI attributes. |
335 | * | ||
336 | * setup the sysfs for EDAC PCI attributes | ||
337 | * assumes edac_subsys has already been initialized | ||
338 | */ | 335 | */ |
339 | static int edac_pci_main_kobj_setup(void) | 336 | static int edac_pci_main_kobj_setup(void) |
340 | { | 337 | { |
@@ -351,11 +348,6 @@ static int edac_pci_main_kobj_setup(void) | |||
351 | * controls and attributes | 348 | * controls and attributes |
352 | */ | 349 | */ |
353 | edac_subsys = edac_get_sysfs_subsys(); | 350 | edac_subsys = edac_get_sysfs_subsys(); |
354 | if (edac_subsys == NULL) { | ||
355 | edac_dbg(1, "no edac_subsys\n"); | ||
356 | err = -ENODEV; | ||
357 | goto decrement_count_fail; | ||
358 | } | ||
359 | 351 | ||
360 | /* Bump the reference count on this module to ensure the | 352 | /* Bump the reference count on this module to ensure the |
361 | * modules isn't unloaded until we deconstruct the top | 353 | * modules isn't unloaded until we deconstruct the top |
@@ -364,7 +356,7 @@ static int edac_pci_main_kobj_setup(void) | |||
364 | if (!try_module_get(THIS_MODULE)) { | 356 | if (!try_module_get(THIS_MODULE)) { |
365 | edac_dbg(1, "try_module_get() failed\n"); | 357 | edac_dbg(1, "try_module_get() failed\n"); |
366 | err = -ENODEV; | 358 | err = -ENODEV; |
367 | goto mod_get_fail; | 359 | goto decrement_count_fail; |
368 | } | 360 | } |
369 | 361 | ||
370 | edac_pci_top_main_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL); | 362 | edac_pci_top_main_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL); |
@@ -399,9 +391,6 @@ kobject_init_and_add_fail: | |||
399 | kzalloc_fail: | 391 | kzalloc_fail: |
400 | module_put(THIS_MODULE); | 392 | module_put(THIS_MODULE); |
401 | 393 | ||
402 | mod_get_fail: | ||
403 | edac_put_sysfs_subsys(); | ||
404 | |||
405 | decrement_count_fail: | 394 | decrement_count_fail: |
406 | /* if are on this error exit, nothing to tear down */ | 395 | /* if are on this error exit, nothing to tear down */ |
407 | atomic_dec(&edac_pci_sysfs_refcount); | 396 | atomic_dec(&edac_pci_sysfs_refcount); |
@@ -426,7 +415,6 @@ static void edac_pci_main_kobj_teardown(void) | |||
426 | if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) { | 415 | if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) { |
427 | edac_dbg(0, "called kobject_put on main kobj\n"); | 416 | edac_dbg(0, "called kobject_put on main kobj\n"); |
428 | kobject_put(edac_pci_top_main_kobj); | 417 | kobject_put(edac_pci_top_main_kobj); |
429 | edac_put_sysfs_subsys(); | ||
430 | } | 418 | } |
431 | } | 419 | } |
432 | 420 | ||
diff --git a/drivers/edac/edac_stub.c b/drivers/edac/edac_stub.c index ff07aae5b7fb..952e411f01f2 100644 --- a/drivers/edac/edac_stub.c +++ b/drivers/edac/edac_stub.c | |||
@@ -26,8 +26,6 @@ EXPORT_SYMBOL_GPL(edac_handlers); | |||
26 | int edac_err_assert = 0; | 26 | int edac_err_assert = 0; |
27 | EXPORT_SYMBOL_GPL(edac_err_assert); | 27 | EXPORT_SYMBOL_GPL(edac_err_assert); |
28 | 28 | ||
29 | static atomic_t edac_subsys_valid = ATOMIC_INIT(0); | ||
30 | |||
31 | int edac_report_status = EDAC_REPORTING_ENABLED; | 29 | int edac_report_status = EDAC_REPORTING_ENABLED; |
32 | EXPORT_SYMBOL_GPL(edac_report_status); | 30 | EXPORT_SYMBOL_GPL(edac_report_status); |
33 | 31 | ||
@@ -68,42 +66,3 @@ void edac_atomic_assert_error(void) | |||
68 | edac_err_assert++; | 66 | edac_err_assert++; |
69 | } | 67 | } |
70 | EXPORT_SYMBOL_GPL(edac_atomic_assert_error); | 68 | EXPORT_SYMBOL_GPL(edac_atomic_assert_error); |
71 | |||
72 | /* | ||
73 | * sysfs object: /sys/devices/system/edac | ||
74 | * need to export to other files | ||
75 | */ | ||
76 | struct bus_type edac_subsys = { | ||
77 | .name = "edac", | ||
78 | .dev_name = "edac", | ||
79 | }; | ||
80 | EXPORT_SYMBOL_GPL(edac_subsys); | ||
81 | |||
82 | /* return pointer to the 'edac' node in sysfs */ | ||
83 | struct bus_type *edac_get_sysfs_subsys(void) | ||
84 | { | ||
85 | int err = 0; | ||
86 | |||
87 | if (atomic_read(&edac_subsys_valid)) | ||
88 | goto out; | ||
89 | |||
90 | /* create the /sys/devices/system/edac directory */ | ||
91 | err = subsys_system_register(&edac_subsys, NULL); | ||
92 | if (err) { | ||
93 | printk(KERN_ERR "Error registering toplevel EDAC sysfs dir\n"); | ||
94 | return NULL; | ||
95 | } | ||
96 | |||
97 | out: | ||
98 | atomic_inc(&edac_subsys_valid); | ||
99 | return &edac_subsys; | ||
100 | } | ||
101 | EXPORT_SYMBOL_GPL(edac_get_sysfs_subsys); | ||
102 | |||
103 | void edac_put_sysfs_subsys(void) | ||
104 | { | ||
105 | /* last user unregisters it */ | ||
106 | if (atomic_dec_and_test(&edac_subsys_valid)) | ||
107 | bus_unregister(&edac_subsys); | ||
108 | } | ||
109 | EXPORT_SYMBOL_GPL(edac_put_sysfs_subsys); | ||
diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c index 40917775dca1..c655162caf08 100644 --- a/drivers/edac/i5100_edac.c +++ b/drivers/edac/i5100_edac.c | |||
@@ -575,9 +575,7 @@ static void i5100_check_error(struct mem_ctl_info *mci) | |||
575 | 575 | ||
576 | static void i5100_refresh_scrubbing(struct work_struct *work) | 576 | static void i5100_refresh_scrubbing(struct work_struct *work) |
577 | { | 577 | { |
578 | struct delayed_work *i5100_scrubbing = container_of(work, | 578 | struct delayed_work *i5100_scrubbing = to_delayed_work(work); |
579 | struct delayed_work, | ||
580 | work); | ||
581 | struct i5100_priv *priv = container_of(i5100_scrubbing, | 579 | struct i5100_priv *priv = container_of(i5100_scrubbing, |
582 | struct i5100_priv, | 580 | struct i5100_priv, |
583 | i5100_scrubbing); | 581 | i5100_scrubbing); |
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index 23ef8e9f2c9a..b7139c160baf 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/edac.h> | 20 | #include <linux/edac.h> |
21 | #include <linux/smp.h> | 21 | #include <linux/smp.h> |
22 | #include <linux/gfp.h> | 22 | #include <linux/gfp.h> |
23 | #include <linux/fsl/edac.h> | ||
23 | 24 | ||
24 | #include <linux/of_platform.h> | 25 | #include <linux/of_platform.h> |
25 | #include <linux/of_device.h> | 26 | #include <linux/of_device.h> |
@@ -238,10 +239,12 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id) | |||
238 | return IRQ_HANDLED; | 239 | return IRQ_HANDLED; |
239 | } | 240 | } |
240 | 241 | ||
241 | int mpc85xx_pci_err_probe(struct platform_device *op) | 242 | static int mpc85xx_pci_err_probe(struct platform_device *op) |
242 | { | 243 | { |
243 | struct edac_pci_ctl_info *pci; | 244 | struct edac_pci_ctl_info *pci; |
244 | struct mpc85xx_pci_pdata *pdata; | 245 | struct mpc85xx_pci_pdata *pdata; |
246 | struct mpc85xx_edac_pci_plat_data *plat_data; | ||
247 | struct device_node *of_node; | ||
245 | struct resource r; | 248 | struct resource r; |
246 | int res = 0; | 249 | int res = 0; |
247 | 250 | ||
@@ -266,7 +269,15 @@ int mpc85xx_pci_err_probe(struct platform_device *op) | |||
266 | pdata->name = "mpc85xx_pci_err"; | 269 | pdata->name = "mpc85xx_pci_err"; |
267 | pdata->irq = NO_IRQ; | 270 | pdata->irq = NO_IRQ; |
268 | 271 | ||
269 | if (mpc85xx_pcie_find_capability(op->dev.of_node) > 0) | 272 | plat_data = op->dev.platform_data; |
273 | if (!plat_data) { | ||
274 | dev_err(&op->dev, "no platform data"); | ||
275 | res = -ENXIO; | ||
276 | goto err; | ||
277 | } | ||
278 | of_node = plat_data->of_node; | ||
279 | |||
280 | if (mpc85xx_pcie_find_capability(of_node) > 0) | ||
270 | pdata->is_pcie = true; | 281 | pdata->is_pcie = true; |
271 | 282 | ||
272 | dev_set_drvdata(&op->dev, pci); | 283 | dev_set_drvdata(&op->dev, pci); |
@@ -284,7 +295,7 @@ int mpc85xx_pci_err_probe(struct platform_device *op) | |||
284 | 295 | ||
285 | pdata->edac_idx = edac_pci_idx++; | 296 | pdata->edac_idx = edac_pci_idx++; |
286 | 297 | ||
287 | res = of_address_to_resource(op->dev.of_node, 0, &r); | 298 | res = of_address_to_resource(of_node, 0, &r); |
288 | if (res) { | 299 | if (res) { |
289 | printk(KERN_ERR "%s: Unable to get resource for " | 300 | printk(KERN_ERR "%s: Unable to get resource for " |
290 | "PCI err regs\n", __func__); | 301 | "PCI err regs\n", __func__); |
@@ -339,7 +350,7 @@ int mpc85xx_pci_err_probe(struct platform_device *op) | |||
339 | } | 350 | } |
340 | 351 | ||
341 | if (edac_op_state == EDAC_OPSTATE_INT) { | 352 | if (edac_op_state == EDAC_OPSTATE_INT) { |
342 | pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); | 353 | pdata->irq = irq_of_parse_and_map(of_node, 0); |
343 | res = devm_request_irq(&op->dev, pdata->irq, | 354 | res = devm_request_irq(&op->dev, pdata->irq, |
344 | mpc85xx_pci_isr, | 355 | mpc85xx_pci_isr, |
345 | IRQF_SHARED, | 356 | IRQF_SHARED, |
@@ -386,8 +397,22 @@ err: | |||
386 | devres_release_group(&op->dev, mpc85xx_pci_err_probe); | 397 | devres_release_group(&op->dev, mpc85xx_pci_err_probe); |
387 | return res; | 398 | return res; |
388 | } | 399 | } |
389 | EXPORT_SYMBOL(mpc85xx_pci_err_probe); | ||
390 | 400 | ||
401 | static const struct platform_device_id mpc85xx_pci_err_match[] = { | ||
402 | { | ||
403 | .name = "mpc85xx-pci-edac" | ||
404 | }, | ||
405 | {} | ||
406 | }; | ||
407 | |||
408 | static struct platform_driver mpc85xx_pci_err_driver = { | ||
409 | .probe = mpc85xx_pci_err_probe, | ||
410 | .id_table = mpc85xx_pci_err_match, | ||
411 | .driver = { | ||
412 | .name = "mpc85xx_pci_err", | ||
413 | .suppress_bind_attrs = true, | ||
414 | }, | ||
415 | }; | ||
391 | #endif /* CONFIG_PCI */ | 416 | #endif /* CONFIG_PCI */ |
392 | 417 | ||
393 | /**************************** L2 Err device ***************************/ | 418 | /**************************** L2 Err device ***************************/ |
@@ -1208,6 +1233,14 @@ static void __init mpc85xx_mc_clear_rfxe(void *data) | |||
1208 | } | 1233 | } |
1209 | #endif | 1234 | #endif |
1210 | 1235 | ||
1236 | static struct platform_driver * const drivers[] = { | ||
1237 | &mpc85xx_mc_err_driver, | ||
1238 | &mpc85xx_l2_err_driver, | ||
1239 | #ifdef CONFIG_PCI | ||
1240 | &mpc85xx_pci_err_driver, | ||
1241 | #endif | ||
1242 | }; | ||
1243 | |||
1211 | static int __init mpc85xx_mc_init(void) | 1244 | static int __init mpc85xx_mc_init(void) |
1212 | { | 1245 | { |
1213 | int res = 0; | 1246 | int res = 0; |
@@ -1226,13 +1259,9 @@ static int __init mpc85xx_mc_init(void) | |||
1226 | break; | 1259 | break; |
1227 | } | 1260 | } |
1228 | 1261 | ||
1229 | res = platform_driver_register(&mpc85xx_mc_err_driver); | 1262 | res = platform_register_drivers(drivers, ARRAY_SIZE(drivers)); |
1230 | if (res) | ||
1231 | printk(KERN_WARNING EDAC_MOD_STR "MC fails to register\n"); | ||
1232 | |||
1233 | res = platform_driver_register(&mpc85xx_l2_err_driver); | ||
1234 | if (res) | 1263 | if (res) |
1235 | printk(KERN_WARNING EDAC_MOD_STR "L2 fails to register\n"); | 1264 | printk(KERN_WARNING EDAC_MOD_STR "drivers fail to register\n"); |
1236 | 1265 | ||
1237 | #ifdef CONFIG_FSL_SOC_BOOKE | 1266 | #ifdef CONFIG_FSL_SOC_BOOKE |
1238 | pvr = mfspr(SPRN_PVR); | 1267 | pvr = mfspr(SPRN_PVR); |
@@ -1270,8 +1299,7 @@ static void __exit mpc85xx_mc_exit(void) | |||
1270 | on_each_cpu(mpc85xx_mc_restore_hid1, NULL, 0); | 1299 | on_each_cpu(mpc85xx_mc_restore_hid1, NULL, 0); |
1271 | } | 1300 | } |
1272 | #endif | 1301 | #endif |
1273 | platform_driver_unregister(&mpc85xx_l2_err_driver); | 1302 | platform_unregister_drivers(drivers, ARRAY_SIZE(drivers)); |
1274 | platform_driver_unregister(&mpc85xx_mc_err_driver); | ||
1275 | } | 1303 | } |
1276 | 1304 | ||
1277 | module_exit(mpc85xx_mc_exit); | 1305 | module_exit(mpc85xx_mc_exit); |
diff --git a/drivers/edac/mv64x60_edac.c b/drivers/edac/mv64x60_edac.c index 0574e1bbe45c..6c54127e6eae 100644 --- a/drivers/edac/mv64x60_edac.c +++ b/drivers/edac/mv64x60_edac.c | |||
@@ -847,6 +847,15 @@ static struct platform_driver mv64x60_mc_err_driver = { | |||
847 | } | 847 | } |
848 | }; | 848 | }; |
849 | 849 | ||
850 | static struct platform_driver * const drivers[] = { | ||
851 | &mv64x60_mc_err_driver, | ||
852 | &mv64x60_cpu_err_driver, | ||
853 | &mv64x60_sram_err_driver, | ||
854 | #ifdef CONFIG_PCI | ||
855 | &mv64x60_pci_err_driver, | ||
856 | #endif | ||
857 | }; | ||
858 | |||
850 | static int __init mv64x60_edac_init(void) | 859 | static int __init mv64x60_edac_init(void) |
851 | { | 860 | { |
852 | int ret = 0; | 861 | int ret = 0; |
@@ -863,39 +872,13 @@ static int __init mv64x60_edac_init(void) | |||
863 | break; | 872 | break; |
864 | } | 873 | } |
865 | 874 | ||
866 | ret = platform_driver_register(&mv64x60_mc_err_driver); | 875 | return platform_register_drivers(drivers, ARRAY_SIZE(drivers)); |
867 | if (ret) | ||
868 | printk(KERN_WARNING EDAC_MOD_STR "MC err failed to register\n"); | ||
869 | |||
870 | ret = platform_driver_register(&mv64x60_cpu_err_driver); | ||
871 | if (ret) | ||
872 | printk(KERN_WARNING EDAC_MOD_STR | ||
873 | "CPU err failed to register\n"); | ||
874 | |||
875 | ret = platform_driver_register(&mv64x60_sram_err_driver); | ||
876 | if (ret) | ||
877 | printk(KERN_WARNING EDAC_MOD_STR | ||
878 | "SRAM err failed to register\n"); | ||
879 | |||
880 | #ifdef CONFIG_PCI | ||
881 | ret = platform_driver_register(&mv64x60_pci_err_driver); | ||
882 | if (ret) | ||
883 | printk(KERN_WARNING EDAC_MOD_STR | ||
884 | "PCI err failed to register\n"); | ||
885 | #endif | ||
886 | |||
887 | return ret; | ||
888 | } | 876 | } |
889 | module_init(mv64x60_edac_init); | 877 | module_init(mv64x60_edac_init); |
890 | 878 | ||
891 | static void __exit mv64x60_edac_exit(void) | 879 | static void __exit mv64x60_edac_exit(void) |
892 | { | 880 | { |
893 | #ifdef CONFIG_PCI | 881 | platform_unregister_drivers(drivers, ARRAY_SIZE(drivers)); |
894 | platform_driver_unregister(&mv64x60_pci_err_driver); | ||
895 | #endif | ||
896 | platform_driver_unregister(&mv64x60_sram_err_driver); | ||
897 | platform_driver_unregister(&mv64x60_cpu_err_driver); | ||
898 | platform_driver_unregister(&mv64x60_mc_err_driver); | ||
899 | } | 882 | } |
900 | module_exit(mv64x60_edac_exit); | 883 | module_exit(mv64x60_edac_exit); |
901 | 884 | ||
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 429309c62699..e438ee5b433f 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c | |||
@@ -65,15 +65,20 @@ static const u32 ibridge_dram_rule[] = { | |||
65 | 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, | 65 | 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, |
66 | }; | 66 | }; |
67 | 67 | ||
68 | #define SAD_LIMIT(reg) ((GET_BITFIELD(reg, 6, 25) << 26) | 0x3ffffff) | 68 | static const u32 knl_dram_rule[] = { |
69 | #define DRAM_ATTR(reg) GET_BITFIELD(reg, 2, 3) | 69 | 0x60, 0x68, 0x70, 0x78, 0x80, /* 0-4 */ |
70 | #define INTERLEAVE_MODE(reg) GET_BITFIELD(reg, 1, 1) | 70 | 0x88, 0x90, 0x98, 0xa0, 0xa8, /* 5-9 */ |
71 | 0xb0, 0xb8, 0xc0, 0xc8, 0xd0, /* 10-14 */ | ||
72 | 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, /* 15-19 */ | ||
73 | 0x100, 0x108, 0x110, 0x118, /* 20-23 */ | ||
74 | }; | ||
75 | |||
71 | #define DRAM_RULE_ENABLE(reg) GET_BITFIELD(reg, 0, 0) | 76 | #define DRAM_RULE_ENABLE(reg) GET_BITFIELD(reg, 0, 0) |
72 | #define A7MODE(reg) GET_BITFIELD(reg, 26, 26) | 77 | #define A7MODE(reg) GET_BITFIELD(reg, 26, 26) |
73 | 78 | ||
74 | static char *get_dram_attr(u32 reg) | 79 | static char *show_dram_attr(u32 attr) |
75 | { | 80 | { |
76 | switch(DRAM_ATTR(reg)) { | 81 | switch (attr) { |
77 | case 0: | 82 | case 0: |
78 | return "DRAM"; | 83 | return "DRAM"; |
79 | case 1: | 84 | case 1: |
@@ -97,6 +102,14 @@ static const u32 ibridge_interleave_list[] = { | |||
97 | 0xdc, 0xe4, 0xec, 0xf4, 0xfc, | 102 | 0xdc, 0xe4, 0xec, 0xf4, 0xfc, |
98 | }; | 103 | }; |
99 | 104 | ||
105 | static const u32 knl_interleave_list[] = { | ||
106 | 0x64, 0x6c, 0x74, 0x7c, 0x84, /* 0-4 */ | ||
107 | 0x8c, 0x94, 0x9c, 0xa4, 0xac, /* 5-9 */ | ||
108 | 0xb4, 0xbc, 0xc4, 0xcc, 0xd4, /* 10-14 */ | ||
109 | 0xdc, 0xe4, 0xec, 0xf4, 0xfc, /* 15-19 */ | ||
110 | 0x104, 0x10c, 0x114, 0x11c, /* 20-23 */ | ||
111 | }; | ||
112 | |||
100 | struct interleave_pkg { | 113 | struct interleave_pkg { |
101 | unsigned char start; | 114 | unsigned char start; |
102 | unsigned char end; | 115 | unsigned char end; |
@@ -134,10 +147,13 @@ static inline int sad_pkg(const struct interleave_pkg *table, u32 reg, | |||
134 | /* Devices 12 Function 7 */ | 147 | /* Devices 12 Function 7 */ |
135 | 148 | ||
136 | #define TOLM 0x80 | 149 | #define TOLM 0x80 |
137 | #define TOHM 0x84 | 150 | #define TOHM 0x84 |
138 | #define HASWELL_TOLM 0xd0 | 151 | #define HASWELL_TOLM 0xd0 |
139 | #define HASWELL_TOHM_0 0xd4 | 152 | #define HASWELL_TOHM_0 0xd4 |
140 | #define HASWELL_TOHM_1 0xd8 | 153 | #define HASWELL_TOHM_1 0xd8 |
154 | #define KNL_TOLM 0xd0 | ||
155 | #define KNL_TOHM_0 0xd4 | ||
156 | #define KNL_TOHM_1 0xd8 | ||
141 | 157 | ||
142 | #define GET_TOLM(reg) ((GET_BITFIELD(reg, 0, 3) << 28) | 0x3ffffff) | 158 | #define GET_TOLM(reg) ((GET_BITFIELD(reg, 0, 3) << 28) | 0x3ffffff) |
143 | #define GET_TOHM(reg) ((GET_BITFIELD(reg, 0, 20) << 25) | 0x3ffffff) | 159 | #define GET_TOHM(reg) ((GET_BITFIELD(reg, 0, 20) << 25) | 0x3ffffff) |
@@ -148,6 +164,8 @@ static inline int sad_pkg(const struct interleave_pkg *table, u32 reg, | |||
148 | 164 | ||
149 | #define SOURCE_ID(reg) GET_BITFIELD(reg, 9, 11) | 165 | #define SOURCE_ID(reg) GET_BITFIELD(reg, 9, 11) |
150 | 166 | ||
167 | #define SOURCE_ID_KNL(reg) GET_BITFIELD(reg, 12, 14) | ||
168 | |||
151 | #define SAD_CONTROL 0xf4 | 169 | #define SAD_CONTROL 0xf4 |
152 | 170 | ||
153 | /* Device 14 function 0 */ | 171 | /* Device 14 function 0 */ |
@@ -170,6 +188,7 @@ static const u32 tad_dram_rule[] = { | |||
170 | /* Device 15, function 0 */ | 188 | /* Device 15, function 0 */ |
171 | 189 | ||
172 | #define MCMTR 0x7c | 190 | #define MCMTR 0x7c |
191 | #define KNL_MCMTR 0x624 | ||
173 | 192 | ||
174 | #define IS_ECC_ENABLED(mcmtr) GET_BITFIELD(mcmtr, 2, 2) | 193 | #define IS_ECC_ENABLED(mcmtr) GET_BITFIELD(mcmtr, 2, 2) |
175 | #define IS_LOCKSTEP_ENABLED(mcmtr) GET_BITFIELD(mcmtr, 1, 1) | 194 | #define IS_LOCKSTEP_ENABLED(mcmtr) GET_BITFIELD(mcmtr, 1, 1) |
@@ -186,6 +205,8 @@ static const int mtr_regs[] = { | |||
186 | 0x80, 0x84, 0x88, | 205 | 0x80, 0x84, 0x88, |
187 | }; | 206 | }; |
188 | 207 | ||
208 | static const int knl_mtr_reg = 0xb60; | ||
209 | |||
189 | #define RANK_DISABLE(mtr) GET_BITFIELD(mtr, 16, 19) | 210 | #define RANK_DISABLE(mtr) GET_BITFIELD(mtr, 16, 19) |
190 | #define IS_DIMM_PRESENT(mtr) GET_BITFIELD(mtr, 14, 14) | 211 | #define IS_DIMM_PRESENT(mtr) GET_BITFIELD(mtr, 14, 14) |
191 | #define RANK_CNT_BITS(mtr) GET_BITFIELD(mtr, 12, 13) | 212 | #define RANK_CNT_BITS(mtr) GET_BITFIELD(mtr, 12, 13) |
@@ -256,6 +277,9 @@ static const u32 correrrthrsld[] = { | |||
256 | 277 | ||
257 | #define NUM_CHANNELS 8 /* 2MC per socket, four chan per MC */ | 278 | #define NUM_CHANNELS 8 /* 2MC per socket, four chan per MC */ |
258 | #define MAX_DIMMS 3 /* Max DIMMS per channel */ | 279 | #define MAX_DIMMS 3 /* Max DIMMS per channel */ |
280 | #define KNL_MAX_CHAS 38 /* KNL max num. of Cache Home Agents */ | ||
281 | #define KNL_MAX_CHANNELS 6 /* KNL max num. of PCI channels */ | ||
282 | #define KNL_MAX_EDCS 8 /* Embedded DRAM controllers */ | ||
259 | #define CHANNEL_UNSPECIFIED 0xf /* Intel IA32 SDM 15-14 */ | 283 | #define CHANNEL_UNSPECIFIED 0xf /* Intel IA32 SDM 15-14 */ |
260 | 284 | ||
261 | enum type { | 285 | enum type { |
@@ -263,6 +287,7 @@ enum type { | |||
263 | IVY_BRIDGE, | 287 | IVY_BRIDGE, |
264 | HASWELL, | 288 | HASWELL, |
265 | BROADWELL, | 289 | BROADWELL, |
290 | KNIGHTS_LANDING, | ||
266 | }; | 291 | }; |
267 | 292 | ||
268 | struct sbridge_pvt; | 293 | struct sbridge_pvt; |
@@ -273,6 +298,10 @@ struct sbridge_info { | |||
273 | u64 (*get_tolm)(struct sbridge_pvt *pvt); | 298 | u64 (*get_tolm)(struct sbridge_pvt *pvt); |
274 | u64 (*get_tohm)(struct sbridge_pvt *pvt); | 299 | u64 (*get_tohm)(struct sbridge_pvt *pvt); |
275 | u64 (*rir_limit)(u32 reg); | 300 | u64 (*rir_limit)(u32 reg); |
301 | u64 (*sad_limit)(u32 reg); | ||
302 | u32 (*interleave_mode)(u32 reg); | ||
303 | char* (*show_interleave_mode)(u32 reg); | ||
304 | u32 (*dram_attr)(u32 reg); | ||
276 | const u32 *dram_rule; | 305 | const u32 *dram_rule; |
277 | const u32 *interleave_list; | 306 | const u32 *interleave_list; |
278 | const struct interleave_pkg *interleave_pkg; | 307 | const struct interleave_pkg *interleave_pkg; |
@@ -308,6 +337,16 @@ struct sbridge_dev { | |||
308 | struct mem_ctl_info *mci; | 337 | struct mem_ctl_info *mci; |
309 | }; | 338 | }; |
310 | 339 | ||
340 | struct knl_pvt { | ||
341 | struct pci_dev *pci_cha[KNL_MAX_CHAS]; | ||
342 | struct pci_dev *pci_channel[KNL_MAX_CHANNELS]; | ||
343 | struct pci_dev *pci_mc0; | ||
344 | struct pci_dev *pci_mc1; | ||
345 | struct pci_dev *pci_mc0_misc; | ||
346 | struct pci_dev *pci_mc1_misc; | ||
347 | struct pci_dev *pci_mc_info; /* tolm, tohm */ | ||
348 | }; | ||
349 | |||
311 | struct sbridge_pvt { | 350 | struct sbridge_pvt { |
312 | struct pci_dev *pci_ta, *pci_ddrio, *pci_ras; | 351 | struct pci_dev *pci_ta, *pci_ddrio, *pci_ras; |
313 | struct pci_dev *pci_sad0, *pci_sad1; | 352 | struct pci_dev *pci_sad0, *pci_sad1; |
@@ -336,6 +375,7 @@ struct sbridge_pvt { | |||
336 | 375 | ||
337 | /* Memory description */ | 376 | /* Memory description */ |
338 | u64 tolm, tohm; | 377 | u64 tolm, tohm; |
378 | struct knl_pvt knl; | ||
339 | }; | 379 | }; |
340 | 380 | ||
341 | #define PCI_DESCR(device_id, opt) \ | 381 | #define PCI_DESCR(device_id, opt) \ |
@@ -509,6 +549,50 @@ static const struct pci_id_table pci_dev_descr_haswell_table[] = { | |||
509 | {0,} /* 0 terminated list. */ | 549 | {0,} /* 0 terminated list. */ |
510 | }; | 550 | }; |
511 | 551 | ||
552 | /* Knight's Landing Support */ | ||
553 | /* | ||
554 | * KNL's memory channels are swizzled between memory controllers. | ||
555 | * MC0 is mapped to CH3,5,6 and MC1 is mapped to CH0,1,2 | ||
556 | */ | ||
557 | #define knl_channel_remap(channel) ((channel + 3) % 6) | ||
558 | |||
559 | /* Memory controller, TAD tables, error injection - 2-8-0, 2-9-0 (2 of these) */ | ||
560 | #define PCI_DEVICE_ID_INTEL_KNL_IMC_MC 0x7840 | ||
561 | /* DRAM channel stuff; bank addrs, dimmmtr, etc.. 2-8-2 - 2-9-4 (6 of these) */ | ||
562 | #define PCI_DEVICE_ID_INTEL_KNL_IMC_CHANNEL 0x7843 | ||
563 | /* kdrwdbu TAD limits/offsets, MCMTR - 2-10-1, 2-11-1 (2 of these) */ | ||
564 | #define PCI_DEVICE_ID_INTEL_KNL_IMC_TA 0x7844 | ||
565 | /* CHA broadcast registers, dram rules - 1-29-0 (1 of these) */ | ||
566 | #define PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0 0x782a | ||
567 | /* SAD target - 1-29-1 (1 of these) */ | ||
568 | #define PCI_DEVICE_ID_INTEL_KNL_IMC_SAD1 0x782b | ||
569 | /* Caching / Home Agent */ | ||
570 | #define PCI_DEVICE_ID_INTEL_KNL_IMC_CHA 0x782c | ||
571 | /* Device with TOLM and TOHM, 0-5-0 (1 of these) */ | ||
572 | #define PCI_DEVICE_ID_INTEL_KNL_IMC_TOLHM 0x7810 | ||
573 | |||
574 | /* | ||
575 | * KNL differs from SB, IB, and Haswell in that it has multiple | ||
576 | * instances of the same device with the same device ID, so we handle that | ||
577 | * by creating as many copies in the table as we expect to find. | ||
578 | * (Like device ID must be grouped together.) | ||
579 | */ | ||
580 | |||
581 | static const struct pci_id_descr pci_dev_descr_knl[] = { | ||
582 | [0] = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0, 0) }, | ||
583 | [1] = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_SAD1, 0) }, | ||
584 | [2 ... 3] = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_MC, 0)}, | ||
585 | [4 ... 41] = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_CHA, 0) }, | ||
586 | [42 ... 47] = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_CHANNEL, 0) }, | ||
587 | [48] = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_TA, 0) }, | ||
588 | [49] = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_TOLHM, 0) }, | ||
589 | }; | ||
590 | |||
591 | static const struct pci_id_table pci_dev_descr_knl_table[] = { | ||
592 | PCI_ID_TABLE_ENTRY(pci_dev_descr_knl), | ||
593 | {0,} | ||
594 | }; | ||
595 | |||
512 | /* | 596 | /* |
513 | * Broadwell support | 597 | * Broadwell support |
514 | * | 598 | * |
@@ -585,6 +669,7 @@ static const struct pci_device_id sbridge_pci_tbl[] = { | |||
585 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)}, | 669 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)}, |
586 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0)}, | 670 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0)}, |
587 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0)}, | 671 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0)}, |
672 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0)}, | ||
588 | {0,} /* 0 terminated list. */ | 673 | {0,} /* 0 terminated list. */ |
589 | }; | 674 | }; |
590 | 675 | ||
@@ -598,7 +683,7 @@ static inline int numrank(enum type type, u32 mtr) | |||
598 | int ranks = (1 << RANK_CNT_BITS(mtr)); | 683 | int ranks = (1 << RANK_CNT_BITS(mtr)); |
599 | int max = 4; | 684 | int max = 4; |
600 | 685 | ||
601 | if (type == HASWELL || type == BROADWELL) | 686 | if (type == HASWELL || type == BROADWELL || type == KNIGHTS_LANDING) |
602 | max = 8; | 687 | max = 8; |
603 | 688 | ||
604 | if (ranks > max) { | 689 | if (ranks > max) { |
@@ -636,10 +721,19 @@ static inline int numcol(u32 mtr) | |||
636 | return 1 << cols; | 721 | return 1 << cols; |
637 | } | 722 | } |
638 | 723 | ||
639 | static struct sbridge_dev *get_sbridge_dev(u8 bus) | 724 | static struct sbridge_dev *get_sbridge_dev(u8 bus, int multi_bus) |
640 | { | 725 | { |
641 | struct sbridge_dev *sbridge_dev; | 726 | struct sbridge_dev *sbridge_dev; |
642 | 727 | ||
728 | /* | ||
729 | * If we have devices scattered across several busses that pertain | ||
730 | * to the same memory controller, we'll lump them all together. | ||
731 | */ | ||
732 | if (multi_bus) { | ||
733 | return list_first_entry_or_null(&sbridge_edac_list, | ||
734 | struct sbridge_dev, list); | ||
735 | } | ||
736 | |||
643 | list_for_each_entry(sbridge_dev, &sbridge_edac_list, list) { | 737 | list_for_each_entry(sbridge_dev, &sbridge_edac_list, list) { |
644 | if (sbridge_dev->bus == bus) | 738 | if (sbridge_dev->bus == bus) |
645 | return sbridge_dev; | 739 | return sbridge_dev; |
@@ -718,6 +812,67 @@ static u64 rir_limit(u32 reg) | |||
718 | return ((u64)GET_BITFIELD(reg, 1, 10) << 29) | 0x1fffffff; | 812 | return ((u64)GET_BITFIELD(reg, 1, 10) << 29) | 0x1fffffff; |
719 | } | 813 | } |
720 | 814 | ||
815 | static u64 sad_limit(u32 reg) | ||
816 | { | ||
817 | return (GET_BITFIELD(reg, 6, 25) << 26) | 0x3ffffff; | ||
818 | } | ||
819 | |||
820 | static u32 interleave_mode(u32 reg) | ||
821 | { | ||
822 | return GET_BITFIELD(reg, 1, 1); | ||
823 | } | ||
824 | |||
825 | char *show_interleave_mode(u32 reg) | ||
826 | { | ||
827 | return interleave_mode(reg) ? "8:6" : "[8:6]XOR[18:16]"; | ||
828 | } | ||
829 | |||
830 | static u32 dram_attr(u32 reg) | ||
831 | { | ||
832 | return GET_BITFIELD(reg, 2, 3); | ||
833 | } | ||
834 | |||
835 | static u64 knl_sad_limit(u32 reg) | ||
836 | { | ||
837 | return (GET_BITFIELD(reg, 7, 26) << 26) | 0x3ffffff; | ||
838 | } | ||
839 | |||
840 | static u32 knl_interleave_mode(u32 reg) | ||
841 | { | ||
842 | return GET_BITFIELD(reg, 1, 2); | ||
843 | } | ||
844 | |||
845 | static char *knl_show_interleave_mode(u32 reg) | ||
846 | { | ||
847 | char *s; | ||
848 | |||
849 | switch (knl_interleave_mode(reg)) { | ||
850 | case 0: | ||
851 | s = "use address bits [8:6]"; | ||
852 | break; | ||
853 | case 1: | ||
854 | s = "use address bits [10:8]"; | ||
855 | break; | ||
856 | case 2: | ||
857 | s = "use address bits [14:12]"; | ||
858 | break; | ||
859 | case 3: | ||
860 | s = "use address bits [32:30]"; | ||
861 | break; | ||
862 | default: | ||
863 | WARN_ON(1); | ||
864 | break; | ||
865 | } | ||
866 | |||
867 | return s; | ||
868 | } | ||
869 | |||
870 | static u32 dram_attr_knl(u32 reg) | ||
871 | { | ||
872 | return GET_BITFIELD(reg, 3, 4); | ||
873 | } | ||
874 | |||
875 | |||
721 | static enum mem_type get_memory_type(struct sbridge_pvt *pvt) | 876 | static enum mem_type get_memory_type(struct sbridge_pvt *pvt) |
722 | { | 877 | { |
723 | u32 reg; | 878 | u32 reg; |
@@ -769,6 +924,12 @@ out: | |||
769 | return mtype; | 924 | return mtype; |
770 | } | 925 | } |
771 | 926 | ||
927 | static enum dev_type knl_get_width(struct sbridge_pvt *pvt, u32 mtr) | ||
928 | { | ||
929 | /* for KNL value is fixed */ | ||
930 | return DEV_X16; | ||
931 | } | ||
932 | |||
772 | static enum dev_type sbridge_get_width(struct sbridge_pvt *pvt, u32 mtr) | 933 | static enum dev_type sbridge_get_width(struct sbridge_pvt *pvt, u32 mtr) |
773 | { | 934 | { |
774 | /* there's no way to figure out */ | 935 | /* there's no way to figure out */ |
@@ -812,6 +973,12 @@ static enum dev_type broadwell_get_width(struct sbridge_pvt *pvt, u32 mtr) | |||
812 | return __ibridge_get_width(GET_BITFIELD(mtr, 8, 9)); | 973 | return __ibridge_get_width(GET_BITFIELD(mtr, 8, 9)); |
813 | } | 974 | } |
814 | 975 | ||
976 | static enum mem_type knl_get_memory_type(struct sbridge_pvt *pvt) | ||
977 | { | ||
978 | /* DDR4 RDIMMS and LRDIMMS are supported */ | ||
979 | return MEM_RDDR4; | ||
980 | } | ||
981 | |||
815 | static u8 get_node_id(struct sbridge_pvt *pvt) | 982 | static u8 get_node_id(struct sbridge_pvt *pvt) |
816 | { | 983 | { |
817 | u32 reg; | 984 | u32 reg; |
@@ -827,6 +994,15 @@ static u8 haswell_get_node_id(struct sbridge_pvt *pvt) | |||
827 | return GET_BITFIELD(reg, 0, 3); | 994 | return GET_BITFIELD(reg, 0, 3); |
828 | } | 995 | } |
829 | 996 | ||
997 | static u8 knl_get_node_id(struct sbridge_pvt *pvt) | ||
998 | { | ||
999 | u32 reg; | ||
1000 | |||
1001 | pci_read_config_dword(pvt->pci_sad1, SAD_CONTROL, ®); | ||
1002 | return GET_BITFIELD(reg, 0, 2); | ||
1003 | } | ||
1004 | |||
1005 | |||
830 | static u64 haswell_get_tolm(struct sbridge_pvt *pvt) | 1006 | static u64 haswell_get_tolm(struct sbridge_pvt *pvt) |
831 | { | 1007 | { |
832 | u32 reg; | 1008 | u32 reg; |
@@ -848,6 +1024,26 @@ static u64 haswell_get_tohm(struct sbridge_pvt *pvt) | |||
848 | return rc | 0x1ffffff; | 1024 | return rc | 0x1ffffff; |
849 | } | 1025 | } |
850 | 1026 | ||
1027 | static u64 knl_get_tolm(struct sbridge_pvt *pvt) | ||
1028 | { | ||
1029 | u32 reg; | ||
1030 | |||
1031 | pci_read_config_dword(pvt->knl.pci_mc_info, KNL_TOLM, ®); | ||
1032 | return (GET_BITFIELD(reg, 26, 31) << 26) | 0x3ffffff; | ||
1033 | } | ||
1034 | |||
1035 | static u64 knl_get_tohm(struct sbridge_pvt *pvt) | ||
1036 | { | ||
1037 | u64 rc; | ||
1038 | u32 reg_lo, reg_hi; | ||
1039 | |||
1040 | pci_read_config_dword(pvt->knl.pci_mc_info, KNL_TOHM_0, ®_lo); | ||
1041 | pci_read_config_dword(pvt->knl.pci_mc_info, KNL_TOHM_1, ®_hi); | ||
1042 | rc = ((u64)reg_hi << 32) | reg_lo; | ||
1043 | return rc | 0x3ffffff; | ||
1044 | } | ||
1045 | |||
1046 | |||
851 | static u64 haswell_rir_limit(u32 reg) | 1047 | static u64 haswell_rir_limit(u32 reg) |
852 | { | 1048 | { |
853 | return (((u64)GET_BITFIELD(reg, 1, 11) + 1) << 29) - 1; | 1049 | return (((u64)GET_BITFIELD(reg, 1, 11) + 1) << 29) - 1; |
@@ -905,11 +1101,22 @@ static int check_if_ecc_is_active(const u8 bus, enum type type) | |||
905 | case BROADWELL: | 1101 | case BROADWELL: |
906 | id = PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA; | 1102 | id = PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA; |
907 | break; | 1103 | break; |
1104 | case KNIGHTS_LANDING: | ||
1105 | /* | ||
1106 | * KNL doesn't group things by bus the same way | ||
1107 | * SB/IB/Haswell does. | ||
1108 | */ | ||
1109 | id = PCI_DEVICE_ID_INTEL_KNL_IMC_TA; | ||
1110 | break; | ||
908 | default: | 1111 | default: |
909 | return -ENODEV; | 1112 | return -ENODEV; |
910 | } | 1113 | } |
911 | 1114 | ||
912 | pdev = get_pdev_same_bus(bus, id); | 1115 | if (type != KNIGHTS_LANDING) |
1116 | pdev = get_pdev_same_bus(bus, id); | ||
1117 | else | ||
1118 | pdev = pci_get_device(PCI_VENDOR_ID_INTEL, id, 0); | ||
1119 | |||
913 | if (!pdev) { | 1120 | if (!pdev) { |
914 | sbridge_printk(KERN_ERR, "Couldn't find PCI device " | 1121 | sbridge_printk(KERN_ERR, "Couldn't find PCI device " |
915 | "%04x:%04x! on bus %02d\n", | 1122 | "%04x:%04x! on bus %02d\n", |
@@ -917,7 +1124,8 @@ static int check_if_ecc_is_active(const u8 bus, enum type type) | |||
917 | return -ENODEV; | 1124 | return -ENODEV; |
918 | } | 1125 | } |
919 | 1126 | ||
920 | pci_read_config_dword(pdev, MCMTR, &mcmtr); | 1127 | pci_read_config_dword(pdev, |
1128 | type == KNIGHTS_LANDING ? KNL_MCMTR : MCMTR, &mcmtr); | ||
921 | if (!IS_ECC_ENABLED(mcmtr)) { | 1129 | if (!IS_ECC_ENABLED(mcmtr)) { |
922 | sbridge_printk(KERN_ERR, "ECC is disabled. Aborting\n"); | 1130 | sbridge_printk(KERN_ERR, "ECC is disabled. Aborting\n"); |
923 | return -ENODEV; | 1131 | return -ENODEV; |
@@ -925,6 +1133,476 @@ static int check_if_ecc_is_active(const u8 bus, enum type type) | |||
925 | return 0; | 1133 | return 0; |
926 | } | 1134 | } |
927 | 1135 | ||
1136 | /* Low bits of TAD limit, and some metadata. */ | ||
1137 | static const u32 knl_tad_dram_limit_lo[] = { | ||
1138 | 0x400, 0x500, 0x600, 0x700, | ||
1139 | 0x800, 0x900, 0xa00, 0xb00, | ||
1140 | }; | ||
1141 | |||
1142 | /* Low bits of TAD offset. */ | ||
1143 | static const u32 knl_tad_dram_offset_lo[] = { | ||
1144 | 0x404, 0x504, 0x604, 0x704, | ||
1145 | 0x804, 0x904, 0xa04, 0xb04, | ||
1146 | }; | ||
1147 | |||
1148 | /* High 16 bits of TAD limit and offset. */ | ||
1149 | static const u32 knl_tad_dram_hi[] = { | ||
1150 | 0x408, 0x508, 0x608, 0x708, | ||
1151 | 0x808, 0x908, 0xa08, 0xb08, | ||
1152 | }; | ||
1153 | |||
1154 | /* Number of ways a tad entry is interleaved. */ | ||
1155 | static const u32 knl_tad_ways[] = { | ||
1156 | 8, 6, 4, 3, 2, 1, | ||
1157 | }; | ||
1158 | |||
1159 | /* | ||
1160 | * Retrieve the n'th Target Address Decode table entry | ||
1161 | * from the memory controller's TAD table. | ||
1162 | * | ||
1163 | * @pvt: driver private data | ||
1164 | * @entry: which entry you want to retrieve | ||
1165 | * @mc: which memory controller (0 or 1) | ||
1166 | * @offset: output tad range offset | ||
1167 | * @limit: output address of first byte above tad range | ||
1168 | * @ways: output number of interleave ways | ||
1169 | * | ||
1170 | * The offset value has curious semantics. It's a sort of running total | ||
1171 | * of the sizes of all the memory regions that aren't mapped in this | ||
1172 | * tad table. | ||
1173 | */ | ||
1174 | static int knl_get_tad(const struct sbridge_pvt *pvt, | ||
1175 | const int entry, | ||
1176 | const int mc, | ||
1177 | u64 *offset, | ||
1178 | u64 *limit, | ||
1179 | int *ways) | ||
1180 | { | ||
1181 | u32 reg_limit_lo, reg_offset_lo, reg_hi; | ||
1182 | struct pci_dev *pci_mc; | ||
1183 | int way_id; | ||
1184 | |||
1185 | switch (mc) { | ||
1186 | case 0: | ||
1187 | pci_mc = pvt->knl.pci_mc0; | ||
1188 | break; | ||
1189 | case 1: | ||
1190 | pci_mc = pvt->knl.pci_mc1; | ||
1191 | break; | ||
1192 | default: | ||
1193 | WARN_ON(1); | ||
1194 | return -EINVAL; | ||
1195 | } | ||
1196 | |||
1197 | pci_read_config_dword(pci_mc, | ||
1198 | knl_tad_dram_limit_lo[entry], ®_limit_lo); | ||
1199 | pci_read_config_dword(pci_mc, | ||
1200 | knl_tad_dram_offset_lo[entry], ®_offset_lo); | ||
1201 | pci_read_config_dword(pci_mc, | ||
1202 | knl_tad_dram_hi[entry], ®_hi); | ||
1203 | |||
1204 | /* Is this TAD entry enabled? */ | ||
1205 | if (!GET_BITFIELD(reg_limit_lo, 0, 0)) | ||
1206 | return -ENODEV; | ||
1207 | |||
1208 | way_id = GET_BITFIELD(reg_limit_lo, 3, 5); | ||
1209 | |||
1210 | if (way_id < ARRAY_SIZE(knl_tad_ways)) { | ||
1211 | *ways = knl_tad_ways[way_id]; | ||
1212 | } else { | ||
1213 | *ways = 0; | ||
1214 | sbridge_printk(KERN_ERR, | ||
1215 | "Unexpected value %d in mc_tad_limit_lo wayness field\n", | ||
1216 | way_id); | ||
1217 | return -ENODEV; | ||
1218 | } | ||
1219 | |||
1220 | /* | ||
1221 | * The least significant 6 bits of base and limit are truncated. | ||
1222 | * For limit, we fill the missing bits with 1s. | ||
1223 | */ | ||
1224 | *offset = ((u64) GET_BITFIELD(reg_offset_lo, 6, 31) << 6) | | ||
1225 | ((u64) GET_BITFIELD(reg_hi, 0, 15) << 32); | ||
1226 | *limit = ((u64) GET_BITFIELD(reg_limit_lo, 6, 31) << 6) | 63 | | ||
1227 | ((u64) GET_BITFIELD(reg_hi, 16, 31) << 32); | ||
1228 | |||
1229 | return 0; | ||
1230 | } | ||
1231 | |||
1232 | /* Determine which memory controller is responsible for a given channel. */ | ||
1233 | static int knl_channel_mc(int channel) | ||
1234 | { | ||
1235 | WARN_ON(channel < 0 || channel >= 6); | ||
1236 | |||
1237 | return channel < 3 ? 1 : 0; | ||
1238 | } | ||
1239 | |||
1240 | /* | ||
1241 | * Get the Nth entry from EDC_ROUTE_TABLE register. | ||
1242 | * (This is the per-tile mapping of logical interleave targets to | ||
1243 | * physical EDC modules.) | ||
1244 | * | ||
1245 | * entry 0: 0:2 | ||
1246 | * 1: 3:5 | ||
1247 | * 2: 6:8 | ||
1248 | * 3: 9:11 | ||
1249 | * 4: 12:14 | ||
1250 | * 5: 15:17 | ||
1251 | * 6: 18:20 | ||
1252 | * 7: 21:23 | ||
1253 | * reserved: 24:31 | ||
1254 | */ | ||
1255 | static u32 knl_get_edc_route(int entry, u32 reg) | ||
1256 | { | ||
1257 | WARN_ON(entry >= KNL_MAX_EDCS); | ||
1258 | return GET_BITFIELD(reg, entry*3, (entry*3)+2); | ||
1259 | } | ||
1260 | |||
1261 | /* | ||
1262 | * Get the Nth entry from MC_ROUTE_TABLE register. | ||
1263 | * (This is the per-tile mapping of logical interleave targets to | ||
1264 | * physical DRAM channels modules.) | ||
1265 | * | ||
1266 | * entry 0: mc 0:2 channel 18:19 | ||
1267 | * 1: mc 3:5 channel 20:21 | ||
1268 | * 2: mc 6:8 channel 22:23 | ||
1269 | * 3: mc 9:11 channel 24:25 | ||
1270 | * 4: mc 12:14 channel 26:27 | ||
1271 | * 5: mc 15:17 channel 28:29 | ||
1272 | * reserved: 30:31 | ||
1273 | * | ||
1274 | * Though we have 3 bits to identify the MC, we should only see | ||
1275 | * the values 0 or 1. | ||
1276 | */ | ||
1277 | |||
1278 | static u32 knl_get_mc_route(int entry, u32 reg) | ||
1279 | { | ||
1280 | int mc, chan; | ||
1281 | |||
1282 | WARN_ON(entry >= KNL_MAX_CHANNELS); | ||
1283 | |||
1284 | mc = GET_BITFIELD(reg, entry*3, (entry*3)+2); | ||
1285 | chan = GET_BITFIELD(reg, (entry*2) + 18, (entry*2) + 18 + 1); | ||
1286 | |||
1287 | return knl_channel_remap(mc*3 + chan); | ||
1288 | } | ||
1289 | |||
1290 | /* | ||
1291 | * Render the EDC_ROUTE register in human-readable form. | ||
1292 | * Output string s should be at least KNL_MAX_EDCS*2 bytes. | ||
1293 | */ | ||
1294 | static void knl_show_edc_route(u32 reg, char *s) | ||
1295 | { | ||
1296 | int i; | ||
1297 | |||
1298 | for (i = 0; i < KNL_MAX_EDCS; i++) { | ||
1299 | s[i*2] = knl_get_edc_route(i, reg) + '0'; | ||
1300 | s[i*2+1] = '-'; | ||
1301 | } | ||
1302 | |||
1303 | s[KNL_MAX_EDCS*2 - 1] = '\0'; | ||
1304 | } | ||
1305 | |||
1306 | /* | ||
1307 | * Render the MC_ROUTE register in human-readable form. | ||
1308 | * Output string s should be at least KNL_MAX_CHANNELS*2 bytes. | ||
1309 | */ | ||
1310 | static void knl_show_mc_route(u32 reg, char *s) | ||
1311 | { | ||
1312 | int i; | ||
1313 | |||
1314 | for (i = 0; i < KNL_MAX_CHANNELS; i++) { | ||
1315 | s[i*2] = knl_get_mc_route(i, reg) + '0'; | ||
1316 | s[i*2+1] = '-'; | ||
1317 | } | ||
1318 | |||
1319 | s[KNL_MAX_CHANNELS*2 - 1] = '\0'; | ||
1320 | } | ||
1321 | |||
1322 | #define KNL_EDC_ROUTE 0xb8 | ||
1323 | #define KNL_MC_ROUTE 0xb4 | ||
1324 | |||
1325 | /* Is this dram rule backed by regular DRAM in flat mode? */ | ||
1326 | #define KNL_EDRAM(reg) GET_BITFIELD(reg, 29, 29) | ||
1327 | |||
1328 | /* Is this dram rule cached? */ | ||
1329 | #define KNL_CACHEABLE(reg) GET_BITFIELD(reg, 28, 28) | ||
1330 | |||
1331 | /* Is this rule backed by edc ? */ | ||
1332 | #define KNL_EDRAM_ONLY(reg) GET_BITFIELD(reg, 29, 29) | ||
1333 | |||
1334 | /* Is this rule backed by DRAM, cacheable in EDRAM? */ | ||
1335 | #define KNL_CACHEABLE(reg) GET_BITFIELD(reg, 28, 28) | ||
1336 | |||
1337 | /* Is this rule mod3? */ | ||
1338 | #define KNL_MOD3(reg) GET_BITFIELD(reg, 27, 27) | ||
1339 | |||
1340 | /* | ||
1341 | * Figure out how big our RAM modules are. | ||
1342 | * | ||
1343 | * The DIMMMTR register in KNL doesn't tell us the size of the DIMMs, so we | ||
1344 | * have to figure this out from the SAD rules, interleave lists, route tables, | ||
1345 | * and TAD rules. | ||
1346 | * | ||
1347 | * SAD rules can have holes in them (e.g. the 3G-4G hole), so we have to | ||
1348 | * inspect the TAD rules to figure out how large the SAD regions really are. | ||
1349 | * | ||
1350 | * When we know the real size of a SAD region and how many ways it's | ||
1351 | * interleaved, we know the individual contribution of each channel to | ||
1352 | * TAD is size/ways. | ||
1353 | * | ||
1354 | * Finally, we have to check whether each channel participates in each SAD | ||
1355 | * region. | ||
1356 | * | ||
1357 | * Fortunately, KNL only supports one DIMM per channel, so once we know how | ||
1358 | * much memory the channel uses, we know the DIMM is at least that large. | ||
1359 | * (The BIOS might possibly choose not to map all available memory, in which | ||
1360 | * case we will underreport the size of the DIMM.) | ||
1361 | * | ||
1362 | * In theory, we could try to determine the EDC sizes as well, but that would | ||
1363 | * only work in flat mode, not in cache mode. | ||
1364 | * | ||
1365 | * @mc_sizes: Output sizes of channels (must have space for KNL_MAX_CHANNELS | ||
1366 | * elements) | ||
1367 | */ | ||
1368 | static int knl_get_dimm_capacity(struct sbridge_pvt *pvt, u64 *mc_sizes) | ||
1369 | { | ||
1370 | u64 sad_base, sad_size, sad_limit = 0; | ||
1371 | u64 tad_base, tad_size, tad_limit, tad_deadspace, tad_livespace; | ||
1372 | int sad_rule = 0; | ||
1373 | int tad_rule = 0; | ||
1374 | int intrlv_ways, tad_ways; | ||
1375 | u32 first_pkg, pkg; | ||
1376 | int i; | ||
1377 | u64 sad_actual_size[2]; /* sad size accounting for holes, per mc */ | ||
1378 | u32 dram_rule, interleave_reg; | ||
1379 | u32 mc_route_reg[KNL_MAX_CHAS]; | ||
1380 | u32 edc_route_reg[KNL_MAX_CHAS]; | ||
1381 | int edram_only; | ||
1382 | char edc_route_string[KNL_MAX_EDCS*2]; | ||
1383 | char mc_route_string[KNL_MAX_CHANNELS*2]; | ||
1384 | int cur_reg_start; | ||
1385 | int mc; | ||
1386 | int channel; | ||
1387 | int way; | ||
1388 | int participants[KNL_MAX_CHANNELS]; | ||
1389 | int participant_count = 0; | ||
1390 | |||
1391 | for (i = 0; i < KNL_MAX_CHANNELS; i++) | ||
1392 | mc_sizes[i] = 0; | ||
1393 | |||
1394 | /* Read the EDC route table in each CHA. */ | ||
1395 | cur_reg_start = 0; | ||
1396 | for (i = 0; i < KNL_MAX_CHAS; i++) { | ||
1397 | pci_read_config_dword(pvt->knl.pci_cha[i], | ||
1398 | KNL_EDC_ROUTE, &edc_route_reg[i]); | ||
1399 | |||
1400 | if (i > 0 && edc_route_reg[i] != edc_route_reg[i-1]) { | ||
1401 | knl_show_edc_route(edc_route_reg[i-1], | ||
1402 | edc_route_string); | ||
1403 | if (cur_reg_start == i-1) | ||
1404 | edac_dbg(0, "edc route table for CHA %d: %s\n", | ||
1405 | cur_reg_start, edc_route_string); | ||
1406 | else | ||
1407 | edac_dbg(0, "edc route table for CHA %d-%d: %s\n", | ||
1408 | cur_reg_start, i-1, edc_route_string); | ||
1409 | cur_reg_start = i; | ||
1410 | } | ||
1411 | } | ||
1412 | knl_show_edc_route(edc_route_reg[i-1], edc_route_string); | ||
1413 | if (cur_reg_start == i-1) | ||
1414 | edac_dbg(0, "edc route table for CHA %d: %s\n", | ||
1415 | cur_reg_start, edc_route_string); | ||
1416 | else | ||
1417 | edac_dbg(0, "edc route table for CHA %d-%d: %s\n", | ||
1418 | cur_reg_start, i-1, edc_route_string); | ||
1419 | |||
1420 | /* Read the MC route table in each CHA. */ | ||
1421 | cur_reg_start = 0; | ||
1422 | for (i = 0; i < KNL_MAX_CHAS; i++) { | ||
1423 | pci_read_config_dword(pvt->knl.pci_cha[i], | ||
1424 | KNL_MC_ROUTE, &mc_route_reg[i]); | ||
1425 | |||
1426 | if (i > 0 && mc_route_reg[i] != mc_route_reg[i-1]) { | ||
1427 | knl_show_mc_route(mc_route_reg[i-1], mc_route_string); | ||
1428 | if (cur_reg_start == i-1) | ||
1429 | edac_dbg(0, "mc route table for CHA %d: %s\n", | ||
1430 | cur_reg_start, mc_route_string); | ||
1431 | else | ||
1432 | edac_dbg(0, "mc route table for CHA %d-%d: %s\n", | ||
1433 | cur_reg_start, i-1, mc_route_string); | ||
1434 | cur_reg_start = i; | ||
1435 | } | ||
1436 | } | ||
1437 | knl_show_mc_route(mc_route_reg[i-1], mc_route_string); | ||
1438 | if (cur_reg_start == i-1) | ||
1439 | edac_dbg(0, "mc route table for CHA %d: %s\n", | ||
1440 | cur_reg_start, mc_route_string); | ||
1441 | else | ||
1442 | edac_dbg(0, "mc route table for CHA %d-%d: %s\n", | ||
1443 | cur_reg_start, i-1, mc_route_string); | ||
1444 | |||
1445 | /* Process DRAM rules */ | ||
1446 | for (sad_rule = 0; sad_rule < pvt->info.max_sad; sad_rule++) { | ||
1447 | /* previous limit becomes the new base */ | ||
1448 | sad_base = sad_limit; | ||
1449 | |||
1450 | pci_read_config_dword(pvt->pci_sad0, | ||
1451 | pvt->info.dram_rule[sad_rule], &dram_rule); | ||
1452 | |||
1453 | if (!DRAM_RULE_ENABLE(dram_rule)) | ||
1454 | break; | ||
1455 | |||
1456 | edram_only = KNL_EDRAM_ONLY(dram_rule); | ||
1457 | |||
1458 | sad_limit = pvt->info.sad_limit(dram_rule)+1; | ||
1459 | sad_size = sad_limit - sad_base; | ||
1460 | |||
1461 | pci_read_config_dword(pvt->pci_sad0, | ||
1462 | pvt->info.interleave_list[sad_rule], &interleave_reg); | ||
1463 | |||
1464 | /* | ||
1465 | * Find out how many ways this dram rule is interleaved. | ||
1466 | * We stop when we see the first channel again. | ||
1467 | */ | ||
1468 | first_pkg = sad_pkg(pvt->info.interleave_pkg, | ||
1469 | interleave_reg, 0); | ||
1470 | for (intrlv_ways = 1; intrlv_ways < 8; intrlv_ways++) { | ||
1471 | pkg = sad_pkg(pvt->info.interleave_pkg, | ||
1472 | interleave_reg, intrlv_ways); | ||
1473 | |||
1474 | if ((pkg & 0x8) == 0) { | ||
1475 | /* | ||
1476 | * 0 bit means memory is non-local, | ||
1477 | * which KNL doesn't support | ||
1478 | */ | ||
1479 | edac_dbg(0, "Unexpected interleave target %d\n", | ||
1480 | pkg); | ||
1481 | return -1; | ||
1482 | } | ||
1483 | |||
1484 | if (pkg == first_pkg) | ||
1485 | break; | ||
1486 | } | ||
1487 | if (KNL_MOD3(dram_rule)) | ||
1488 | intrlv_ways *= 3; | ||
1489 | |||
1490 | edac_dbg(3, "dram rule %d (base 0x%llx, limit 0x%llx), %d way interleave%s\n", | ||
1491 | sad_rule, | ||
1492 | sad_base, | ||
1493 | sad_limit, | ||
1494 | intrlv_ways, | ||
1495 | edram_only ? ", EDRAM" : ""); | ||
1496 | |||
1497 | /* | ||
1498 | * Find out how big the SAD region really is by iterating | ||
1499 | * over TAD tables (SAD regions may contain holes). | ||
1500 | * Each memory controller might have a different TAD table, so | ||
1501 | * we have to look at both. | ||
1502 | * | ||
1503 | * Livespace is the memory that's mapped in this TAD table, | ||
1504 | * deadspace is the holes (this could be the MMIO hole, or it | ||
1505 | * could be memory that's mapped by the other TAD table but | ||
1506 | * not this one). | ||
1507 | */ | ||
1508 | for (mc = 0; mc < 2; mc++) { | ||
1509 | sad_actual_size[mc] = 0; | ||
1510 | tad_livespace = 0; | ||
1511 | for (tad_rule = 0; | ||
1512 | tad_rule < ARRAY_SIZE( | ||
1513 | knl_tad_dram_limit_lo); | ||
1514 | tad_rule++) { | ||
1515 | if (knl_get_tad(pvt, | ||
1516 | tad_rule, | ||
1517 | mc, | ||
1518 | &tad_deadspace, | ||
1519 | &tad_limit, | ||
1520 | &tad_ways)) | ||
1521 | break; | ||
1522 | |||
1523 | tad_size = (tad_limit+1) - | ||
1524 | (tad_livespace + tad_deadspace); | ||
1525 | tad_livespace += tad_size; | ||
1526 | tad_base = (tad_limit+1) - tad_size; | ||
1527 | |||
1528 | if (tad_base < sad_base) { | ||
1529 | if (tad_limit > sad_base) | ||
1530 | edac_dbg(0, "TAD region overlaps lower SAD boundary -- TAD tables may be configured incorrectly.\n"); | ||
1531 | } else if (tad_base < sad_limit) { | ||
1532 | if (tad_limit+1 > sad_limit) { | ||
1533 | edac_dbg(0, "TAD region overlaps upper SAD boundary -- TAD tables may be configured incorrectly.\n"); | ||
1534 | } else { | ||
1535 | /* TAD region is completely inside SAD region */ | ||
1536 | edac_dbg(3, "TAD region %d 0x%llx - 0x%llx (%lld bytes) table%d\n", | ||
1537 | tad_rule, tad_base, | ||
1538 | tad_limit, tad_size, | ||
1539 | mc); | ||
1540 | sad_actual_size[mc] += tad_size; | ||
1541 | } | ||
1542 | } | ||
1543 | tad_base = tad_limit+1; | ||
1544 | } | ||
1545 | } | ||
1546 | |||
1547 | for (mc = 0; mc < 2; mc++) { | ||
1548 | edac_dbg(3, " total TAD DRAM footprint in table%d : 0x%llx (%lld bytes)\n", | ||
1549 | mc, sad_actual_size[mc], sad_actual_size[mc]); | ||
1550 | } | ||
1551 | |||
1552 | /* Ignore EDRAM rule */ | ||
1553 | if (edram_only) | ||
1554 | continue; | ||
1555 | |||
1556 | /* Figure out which channels participate in interleave. */ | ||
1557 | for (channel = 0; channel < KNL_MAX_CHANNELS; channel++) | ||
1558 | participants[channel] = 0; | ||
1559 | |||
1560 | /* For each channel, does at least one CHA have | ||
1561 | * this channel mapped to the given target? | ||
1562 | */ | ||
1563 | for (channel = 0; channel < KNL_MAX_CHANNELS; channel++) { | ||
1564 | for (way = 0; way < intrlv_ways; way++) { | ||
1565 | int target; | ||
1566 | int cha; | ||
1567 | |||
1568 | if (KNL_MOD3(dram_rule)) | ||
1569 | target = way; | ||
1570 | else | ||
1571 | target = 0x7 & sad_pkg( | ||
1572 | pvt->info.interleave_pkg, interleave_reg, way); | ||
1573 | |||
1574 | for (cha = 0; cha < KNL_MAX_CHAS; cha++) { | ||
1575 | if (knl_get_mc_route(target, | ||
1576 | mc_route_reg[cha]) == channel | ||
1577 | && participants[channel]) { | ||
1578 | participant_count++; | ||
1579 | participants[channel] = 1; | ||
1580 | break; | ||
1581 | } | ||
1582 | } | ||
1583 | } | ||
1584 | } | ||
1585 | |||
1586 | if (participant_count != intrlv_ways) | ||
1587 | edac_dbg(0, "participant_count (%d) != interleave_ways (%d): DIMM size may be incorrect\n", | ||
1588 | participant_count, intrlv_ways); | ||
1589 | |||
1590 | for (channel = 0; channel < KNL_MAX_CHANNELS; channel++) { | ||
1591 | mc = knl_channel_mc(channel); | ||
1592 | if (participants[channel]) { | ||
1593 | edac_dbg(4, "mc channel %d contributes %lld bytes via sad entry %d\n", | ||
1594 | channel, | ||
1595 | sad_actual_size[mc]/intrlv_ways, | ||
1596 | sad_rule); | ||
1597 | mc_sizes[channel] += | ||
1598 | sad_actual_size[mc]/intrlv_ways; | ||
1599 | } | ||
1600 | } | ||
1601 | } | ||
1602 | |||
1603 | return 0; | ||
1604 | } | ||
1605 | |||
928 | static int get_dimm_config(struct mem_ctl_info *mci) | 1606 | static int get_dimm_config(struct mem_ctl_info *mci) |
929 | { | 1607 | { |
930 | struct sbridge_pvt *pvt = mci->pvt_info; | 1608 | struct sbridge_pvt *pvt = mci->pvt_info; |
@@ -934,13 +1612,20 @@ static int get_dimm_config(struct mem_ctl_info *mci) | |||
934 | u32 reg; | 1612 | u32 reg; |
935 | enum edac_type mode; | 1613 | enum edac_type mode; |
936 | enum mem_type mtype; | 1614 | enum mem_type mtype; |
1615 | int channels = pvt->info.type == KNIGHTS_LANDING ? | ||
1616 | KNL_MAX_CHANNELS : NUM_CHANNELS; | ||
1617 | u64 knl_mc_sizes[KNL_MAX_CHANNELS]; | ||
937 | 1618 | ||
938 | if (pvt->info.type == HASWELL || pvt->info.type == BROADWELL) | 1619 | if (pvt->info.type == HASWELL || pvt->info.type == BROADWELL || |
1620 | pvt->info.type == KNIGHTS_LANDING) | ||
939 | pci_read_config_dword(pvt->pci_sad1, SAD_TARGET, ®); | 1621 | pci_read_config_dword(pvt->pci_sad1, SAD_TARGET, ®); |
940 | else | 1622 | else |
941 | pci_read_config_dword(pvt->pci_br0, SAD_TARGET, ®); | 1623 | pci_read_config_dword(pvt->pci_br0, SAD_TARGET, ®); |
942 | 1624 | ||
943 | pvt->sbridge_dev->source_id = SOURCE_ID(reg); | 1625 | if (pvt->info.type == KNIGHTS_LANDING) |
1626 | pvt->sbridge_dev->source_id = SOURCE_ID_KNL(reg); | ||
1627 | else | ||
1628 | pvt->sbridge_dev->source_id = SOURCE_ID(reg); | ||
944 | 1629 | ||
945 | pvt->sbridge_dev->node_id = pvt->info.get_node_id(pvt); | 1630 | pvt->sbridge_dev->node_id = pvt->info.get_node_id(pvt); |
946 | edac_dbg(0, "mc#%d: Node ID: %d, source ID: %d\n", | 1631 | edac_dbg(0, "mc#%d: Node ID: %d, source ID: %d\n", |
@@ -948,31 +1633,42 @@ static int get_dimm_config(struct mem_ctl_info *mci) | |||
948 | pvt->sbridge_dev->node_id, | 1633 | pvt->sbridge_dev->node_id, |
949 | pvt->sbridge_dev->source_id); | 1634 | pvt->sbridge_dev->source_id); |
950 | 1635 | ||
951 | pci_read_config_dword(pvt->pci_ras, RASENABLES, ®); | 1636 | /* KNL doesn't support mirroring or lockstep, |
952 | if (IS_MIRROR_ENABLED(reg)) { | 1637 | * and is always closed page |
953 | edac_dbg(0, "Memory mirror is enabled\n"); | 1638 | */ |
954 | pvt->is_mirrored = true; | 1639 | if (pvt->info.type == KNIGHTS_LANDING) { |
955 | } else { | 1640 | mode = EDAC_S4ECD4ED; |
956 | edac_dbg(0, "Memory mirror is disabled\n"); | ||
957 | pvt->is_mirrored = false; | 1641 | pvt->is_mirrored = false; |
958 | } | ||
959 | 1642 | ||
960 | pci_read_config_dword(pvt->pci_ta, MCMTR, &pvt->info.mcmtr); | 1643 | if (knl_get_dimm_capacity(pvt, knl_mc_sizes) != 0) |
961 | if (IS_LOCKSTEP_ENABLED(pvt->info.mcmtr)) { | 1644 | return -1; |
962 | edac_dbg(0, "Lockstep is enabled\n"); | ||
963 | mode = EDAC_S8ECD8ED; | ||
964 | pvt->is_lockstep = true; | ||
965 | } else { | 1645 | } else { |
966 | edac_dbg(0, "Lockstep is disabled\n"); | 1646 | pci_read_config_dword(pvt->pci_ras, RASENABLES, ®); |
967 | mode = EDAC_S4ECD4ED; | 1647 | if (IS_MIRROR_ENABLED(reg)) { |
968 | pvt->is_lockstep = false; | 1648 | edac_dbg(0, "Memory mirror is enabled\n"); |
969 | } | 1649 | pvt->is_mirrored = true; |
970 | if (IS_CLOSE_PG(pvt->info.mcmtr)) { | 1650 | } else { |
971 | edac_dbg(0, "address map is on closed page mode\n"); | 1651 | edac_dbg(0, "Memory mirror is disabled\n"); |
972 | pvt->is_close_pg = true; | 1652 | pvt->is_mirrored = false; |
973 | } else { | 1653 | } |
974 | edac_dbg(0, "address map is on open page mode\n"); | 1654 | |
975 | pvt->is_close_pg = false; | 1655 | pci_read_config_dword(pvt->pci_ta, MCMTR, &pvt->info.mcmtr); |
1656 | if (IS_LOCKSTEP_ENABLED(pvt->info.mcmtr)) { | ||
1657 | edac_dbg(0, "Lockstep is enabled\n"); | ||
1658 | mode = EDAC_S8ECD8ED; | ||
1659 | pvt->is_lockstep = true; | ||
1660 | } else { | ||
1661 | edac_dbg(0, "Lockstep is disabled\n"); | ||
1662 | mode = EDAC_S4ECD4ED; | ||
1663 | pvt->is_lockstep = false; | ||
1664 | } | ||
1665 | if (IS_CLOSE_PG(pvt->info.mcmtr)) { | ||
1666 | edac_dbg(0, "address map is on closed page mode\n"); | ||
1667 | pvt->is_close_pg = true; | ||
1668 | } else { | ||
1669 | edac_dbg(0, "address map is on open page mode\n"); | ||
1670 | pvt->is_close_pg = false; | ||
1671 | } | ||
976 | } | 1672 | } |
977 | 1673 | ||
978 | mtype = pvt->info.get_memory_type(pvt); | 1674 | mtype = pvt->info.get_memory_type(pvt); |
@@ -988,23 +1684,46 @@ static int get_dimm_config(struct mem_ctl_info *mci) | |||
988 | else | 1684 | else |
989 | banks = 8; | 1685 | banks = 8; |
990 | 1686 | ||
991 | for (i = 0; i < NUM_CHANNELS; i++) { | 1687 | for (i = 0; i < channels; i++) { |
992 | u32 mtr; | 1688 | u32 mtr; |
993 | 1689 | ||
994 | if (!pvt->pci_tad[i]) | 1690 | int max_dimms_per_channel; |
995 | continue; | 1691 | |
996 | for (j = 0; j < ARRAY_SIZE(mtr_regs); j++) { | 1692 | if (pvt->info.type == KNIGHTS_LANDING) { |
1693 | max_dimms_per_channel = 1; | ||
1694 | if (!pvt->knl.pci_channel[i]) | ||
1695 | continue; | ||
1696 | } else { | ||
1697 | max_dimms_per_channel = ARRAY_SIZE(mtr_regs); | ||
1698 | if (!pvt->pci_tad[i]) | ||
1699 | continue; | ||
1700 | } | ||
1701 | |||
1702 | for (j = 0; j < max_dimms_per_channel; j++) { | ||
997 | dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, mci->n_layers, | 1703 | dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, mci->n_layers, |
998 | i, j, 0); | 1704 | i, j, 0); |
999 | pci_read_config_dword(pvt->pci_tad[i], | 1705 | if (pvt->info.type == KNIGHTS_LANDING) { |
1000 | mtr_regs[j], &mtr); | 1706 | pci_read_config_dword(pvt->knl.pci_channel[i], |
1707 | knl_mtr_reg, &mtr); | ||
1708 | } else { | ||
1709 | pci_read_config_dword(pvt->pci_tad[i], | ||
1710 | mtr_regs[j], &mtr); | ||
1711 | } | ||
1001 | edac_dbg(4, "Channel #%d MTR%d = %x\n", i, j, mtr); | 1712 | edac_dbg(4, "Channel #%d MTR%d = %x\n", i, j, mtr); |
1002 | if (IS_DIMM_PRESENT(mtr)) { | 1713 | if (IS_DIMM_PRESENT(mtr)) { |
1003 | pvt->channel[i].dimms++; | 1714 | pvt->channel[i].dimms++; |
1004 | 1715 | ||
1005 | ranks = numrank(pvt->info.type, mtr); | 1716 | ranks = numrank(pvt->info.type, mtr); |
1006 | rows = numrow(mtr); | 1717 | |
1007 | cols = numcol(mtr); | 1718 | if (pvt->info.type == KNIGHTS_LANDING) { |
1719 | /* For DDR4, this is fixed. */ | ||
1720 | cols = 1 << 10; | ||
1721 | rows = knl_mc_sizes[i] / | ||
1722 | ((u64) cols * ranks * banks * 8); | ||
1723 | } else { | ||
1724 | rows = numrow(mtr); | ||
1725 | cols = numcol(mtr); | ||
1726 | } | ||
1008 | 1727 | ||
1009 | size = ((u64)rows * cols * banks * ranks) >> (20 - 3); | 1728 | size = ((u64)rows * cols * banks * ranks) >> (20 - 3); |
1010 | npages = MiB_TO_PAGES(size); | 1729 | npages = MiB_TO_PAGES(size); |
@@ -1069,7 +1788,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci) | |||
1069 | /* SAD_LIMIT Address range is 45:26 */ | 1788 | /* SAD_LIMIT Address range is 45:26 */ |
1070 | pci_read_config_dword(pvt->pci_sad0, pvt->info.dram_rule[n_sads], | 1789 | pci_read_config_dword(pvt->pci_sad0, pvt->info.dram_rule[n_sads], |
1071 | ®); | 1790 | ®); |
1072 | limit = SAD_LIMIT(reg); | 1791 | limit = pvt->info.sad_limit(reg); |
1073 | 1792 | ||
1074 | if (!DRAM_RULE_ENABLE(reg)) | 1793 | if (!DRAM_RULE_ENABLE(reg)) |
1075 | continue; | 1794 | continue; |
@@ -1081,10 +1800,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci) | |||
1081 | gb = div_u64_rem(tmp_mb, 1024, &mb); | 1800 | gb = div_u64_rem(tmp_mb, 1024, &mb); |
1082 | edac_dbg(0, "SAD#%d %s up to %u.%03u GB (0x%016Lx) Interleave: %s reg=0x%08x\n", | 1801 | edac_dbg(0, "SAD#%d %s up to %u.%03u GB (0x%016Lx) Interleave: %s reg=0x%08x\n", |
1083 | n_sads, | 1802 | n_sads, |
1084 | get_dram_attr(reg), | 1803 | show_dram_attr(pvt->info.dram_attr(reg)), |
1085 | gb, (mb*1000)/1024, | 1804 | gb, (mb*1000)/1024, |
1086 | ((u64)tmp_mb) << 20L, | 1805 | ((u64)tmp_mb) << 20L, |
1087 | INTERLEAVE_MODE(reg) ? "8:6" : "[8:6]XOR[18:16]", | 1806 | pvt->info.show_interleave_mode(reg), |
1088 | reg); | 1807 | reg); |
1089 | prv = limit; | 1808 | prv = limit; |
1090 | 1809 | ||
@@ -1101,6 +1820,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci) | |||
1101 | } | 1820 | } |
1102 | } | 1821 | } |
1103 | 1822 | ||
1823 | if (pvt->info.type == KNIGHTS_LANDING) | ||
1824 | return; | ||
1825 | |||
1104 | /* | 1826 | /* |
1105 | * Step 3) Get TAD range | 1827 | * Step 3) Get TAD range |
1106 | */ | 1828 | */ |
@@ -1248,7 +1970,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
1248 | if (!DRAM_RULE_ENABLE(reg)) | 1970 | if (!DRAM_RULE_ENABLE(reg)) |
1249 | continue; | 1971 | continue; |
1250 | 1972 | ||
1251 | limit = SAD_LIMIT(reg); | 1973 | limit = pvt->info.sad_limit(reg); |
1252 | if (limit <= prv) { | 1974 | if (limit <= prv) { |
1253 | sprintf(msg, "Can't discover the memory socket"); | 1975 | sprintf(msg, "Can't discover the memory socket"); |
1254 | return -EINVAL; | 1976 | return -EINVAL; |
@@ -1262,8 +1984,8 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
1262 | return -EINVAL; | 1984 | return -EINVAL; |
1263 | } | 1985 | } |
1264 | dram_rule = reg; | 1986 | dram_rule = reg; |
1265 | *area_type = get_dram_attr(dram_rule); | 1987 | *area_type = show_dram_attr(pvt->info.dram_attr(dram_rule)); |
1266 | interleave_mode = INTERLEAVE_MODE(dram_rule); | 1988 | interleave_mode = pvt->info.interleave_mode(dram_rule); |
1267 | 1989 | ||
1268 | pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads], | 1990 | pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads], |
1269 | ®); | 1991 | ®); |
@@ -1567,7 +2289,8 @@ static void sbridge_put_all_devices(void) | |||
1567 | static int sbridge_get_onedevice(struct pci_dev **prev, | 2289 | static int sbridge_get_onedevice(struct pci_dev **prev, |
1568 | u8 *num_mc, | 2290 | u8 *num_mc, |
1569 | const struct pci_id_table *table, | 2291 | const struct pci_id_table *table, |
1570 | const unsigned devno) | 2292 | const unsigned devno, |
2293 | const int multi_bus) | ||
1571 | { | 2294 | { |
1572 | struct sbridge_dev *sbridge_dev; | 2295 | struct sbridge_dev *sbridge_dev; |
1573 | const struct pci_id_descr *dev_descr = &table->descr[devno]; | 2296 | const struct pci_id_descr *dev_descr = &table->descr[devno]; |
@@ -1603,7 +2326,7 @@ static int sbridge_get_onedevice(struct pci_dev **prev, | |||
1603 | } | 2326 | } |
1604 | bus = pdev->bus->number; | 2327 | bus = pdev->bus->number; |
1605 | 2328 | ||
1606 | sbridge_dev = get_sbridge_dev(bus); | 2329 | sbridge_dev = get_sbridge_dev(bus, multi_bus); |
1607 | if (!sbridge_dev) { | 2330 | if (!sbridge_dev) { |
1608 | sbridge_dev = alloc_sbridge_dev(bus, table); | 2331 | sbridge_dev = alloc_sbridge_dev(bus, table); |
1609 | if (!sbridge_dev) { | 2332 | if (!sbridge_dev) { |
@@ -1652,21 +2375,32 @@ static int sbridge_get_onedevice(struct pci_dev **prev, | |||
1652 | * @num_mc: pointer to the memory controllers count, to be incremented in case | 2375 | * @num_mc: pointer to the memory controllers count, to be incremented in case |
1653 | * of success. | 2376 | * of success. |
1654 | * @table: model specific table | 2377 | * @table: model specific table |
2378 | * @allow_dups: allow for multiple devices to exist with the same device id | ||
2379 | * (as implemented, this isn't expected to work correctly in the | ||
2380 | * multi-socket case). | ||
2381 | * @multi_bus: don't assume devices on different buses belong to different | ||
2382 | * memory controllers. | ||
1655 | * | 2383 | * |
1656 | * returns 0 in case of success or error code | 2384 | * returns 0 in case of success or error code |
1657 | */ | 2385 | */ |
1658 | static int sbridge_get_all_devices(u8 *num_mc, | 2386 | static int sbridge_get_all_devices_full(u8 *num_mc, |
1659 | const struct pci_id_table *table) | 2387 | const struct pci_id_table *table, |
2388 | int allow_dups, | ||
2389 | int multi_bus) | ||
1660 | { | 2390 | { |
1661 | int i, rc; | 2391 | int i, rc; |
1662 | struct pci_dev *pdev = NULL; | 2392 | struct pci_dev *pdev = NULL; |
1663 | 2393 | ||
1664 | while (table && table->descr) { | 2394 | while (table && table->descr) { |
1665 | for (i = 0; i < table->n_devs; i++) { | 2395 | for (i = 0; i < table->n_devs; i++) { |
1666 | pdev = NULL; | 2396 | if (!allow_dups || i == 0 || |
2397 | table->descr[i].dev_id != | ||
2398 | table->descr[i-1].dev_id) { | ||
2399 | pdev = NULL; | ||
2400 | } | ||
1667 | do { | 2401 | do { |
1668 | rc = sbridge_get_onedevice(&pdev, num_mc, | 2402 | rc = sbridge_get_onedevice(&pdev, num_mc, |
1669 | table, i); | 2403 | table, i, multi_bus); |
1670 | if (rc < 0) { | 2404 | if (rc < 0) { |
1671 | if (i == 0) { | 2405 | if (i == 0) { |
1672 | i = table->n_devs; | 2406 | i = table->n_devs; |
@@ -1675,7 +2409,7 @@ static int sbridge_get_all_devices(u8 *num_mc, | |||
1675 | sbridge_put_all_devices(); | 2409 | sbridge_put_all_devices(); |
1676 | return -ENODEV; | 2410 | return -ENODEV; |
1677 | } | 2411 | } |
1678 | } while (pdev); | 2412 | } while (pdev && !allow_dups); |
1679 | } | 2413 | } |
1680 | table++; | 2414 | table++; |
1681 | } | 2415 | } |
@@ -1683,6 +2417,11 @@ static int sbridge_get_all_devices(u8 *num_mc, | |||
1683 | return 0; | 2417 | return 0; |
1684 | } | 2418 | } |
1685 | 2419 | ||
2420 | #define sbridge_get_all_devices(num_mc, table) \ | ||
2421 | sbridge_get_all_devices_full(num_mc, table, 0, 0) | ||
2422 | #define sbridge_get_all_devices_knl(num_mc, table) \ | ||
2423 | sbridge_get_all_devices_full(num_mc, table, 1, 1) | ||
2424 | |||
1686 | static int sbridge_mci_bind_devs(struct mem_ctl_info *mci, | 2425 | static int sbridge_mci_bind_devs(struct mem_ctl_info *mci, |
1687 | struct sbridge_dev *sbridge_dev) | 2426 | struct sbridge_dev *sbridge_dev) |
1688 | { | 2427 | { |
@@ -2038,6 +2777,131 @@ enodev: | |||
2038 | return -ENODEV; | 2777 | return -ENODEV; |
2039 | } | 2778 | } |
2040 | 2779 | ||
2780 | static int knl_mci_bind_devs(struct mem_ctl_info *mci, | ||
2781 | struct sbridge_dev *sbridge_dev) | ||
2782 | { | ||
2783 | struct sbridge_pvt *pvt = mci->pvt_info; | ||
2784 | struct pci_dev *pdev; | ||
2785 | int dev, func; | ||
2786 | |||
2787 | int i; | ||
2788 | int devidx; | ||
2789 | |||
2790 | for (i = 0; i < sbridge_dev->n_devs; i++) { | ||
2791 | pdev = sbridge_dev->pdev[i]; | ||
2792 | if (!pdev) | ||
2793 | continue; | ||
2794 | |||
2795 | /* Extract PCI device and function. */ | ||
2796 | dev = (pdev->devfn >> 3) & 0x1f; | ||
2797 | func = pdev->devfn & 0x7; | ||
2798 | |||
2799 | switch (pdev->device) { | ||
2800 | case PCI_DEVICE_ID_INTEL_KNL_IMC_MC: | ||
2801 | if (dev == 8) | ||
2802 | pvt->knl.pci_mc0 = pdev; | ||
2803 | else if (dev == 9) | ||
2804 | pvt->knl.pci_mc1 = pdev; | ||
2805 | else { | ||
2806 | sbridge_printk(KERN_ERR, | ||
2807 | "Memory controller in unexpected place! (dev %d, fn %d)\n", | ||
2808 | dev, func); | ||
2809 | continue; | ||
2810 | } | ||
2811 | break; | ||
2812 | |||
2813 | case PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0: | ||
2814 | pvt->pci_sad0 = pdev; | ||
2815 | break; | ||
2816 | |||
2817 | case PCI_DEVICE_ID_INTEL_KNL_IMC_SAD1: | ||
2818 | pvt->pci_sad1 = pdev; | ||
2819 | break; | ||
2820 | |||
2821 | case PCI_DEVICE_ID_INTEL_KNL_IMC_CHA: | ||
2822 | /* There are one of these per tile, and range from | ||
2823 | * 1.14.0 to 1.18.5. | ||
2824 | */ | ||
2825 | devidx = ((dev-14)*8)+func; | ||
2826 | |||
2827 | if (devidx < 0 || devidx >= KNL_MAX_CHAS) { | ||
2828 | sbridge_printk(KERN_ERR, | ||
2829 | "Caching and Home Agent in unexpected place! (dev %d, fn %d)\n", | ||
2830 | dev, func); | ||
2831 | continue; | ||
2832 | } | ||
2833 | |||
2834 | WARN_ON(pvt->knl.pci_cha[devidx] != NULL); | ||
2835 | |||
2836 | pvt->knl.pci_cha[devidx] = pdev; | ||
2837 | break; | ||
2838 | |||
2839 | case PCI_DEVICE_ID_INTEL_KNL_IMC_CHANNEL: | ||
2840 | devidx = -1; | ||
2841 | |||
2842 | /* | ||
2843 | * MC0 channels 0-2 are device 9 function 2-4, | ||
2844 | * MC1 channels 3-5 are device 8 function 2-4. | ||
2845 | */ | ||
2846 | |||
2847 | if (dev == 9) | ||
2848 | devidx = func-2; | ||
2849 | else if (dev == 8) | ||
2850 | devidx = 3 + (func-2); | ||
2851 | |||
2852 | if (devidx < 0 || devidx >= KNL_MAX_CHANNELS) { | ||
2853 | sbridge_printk(KERN_ERR, | ||
2854 | "DRAM Channel Registers in unexpected place! (dev %d, fn %d)\n", | ||
2855 | dev, func); | ||
2856 | continue; | ||
2857 | } | ||
2858 | |||
2859 | WARN_ON(pvt->knl.pci_channel[devidx] != NULL); | ||
2860 | pvt->knl.pci_channel[devidx] = pdev; | ||
2861 | break; | ||
2862 | |||
2863 | case PCI_DEVICE_ID_INTEL_KNL_IMC_TOLHM: | ||
2864 | pvt->knl.pci_mc_info = pdev; | ||
2865 | break; | ||
2866 | |||
2867 | case PCI_DEVICE_ID_INTEL_KNL_IMC_TA: | ||
2868 | pvt->pci_ta = pdev; | ||
2869 | break; | ||
2870 | |||
2871 | default: | ||
2872 | sbridge_printk(KERN_ERR, "Unexpected device %d\n", | ||
2873 | pdev->device); | ||
2874 | break; | ||
2875 | } | ||
2876 | } | ||
2877 | |||
2878 | if (!pvt->knl.pci_mc0 || !pvt->knl.pci_mc1 || | ||
2879 | !pvt->pci_sad0 || !pvt->pci_sad1 || | ||
2880 | !pvt->pci_ta) { | ||
2881 | goto enodev; | ||
2882 | } | ||
2883 | |||
2884 | for (i = 0; i < KNL_MAX_CHANNELS; i++) { | ||
2885 | if (!pvt->knl.pci_channel[i]) { | ||
2886 | sbridge_printk(KERN_ERR, "Missing channel %d\n", i); | ||
2887 | goto enodev; | ||
2888 | } | ||
2889 | } | ||
2890 | |||
2891 | for (i = 0; i < KNL_MAX_CHAS; i++) { | ||
2892 | if (!pvt->knl.pci_cha[i]) { | ||
2893 | sbridge_printk(KERN_ERR, "Missing CHA %d\n", i); | ||
2894 | goto enodev; | ||
2895 | } | ||
2896 | } | ||
2897 | |||
2898 | return 0; | ||
2899 | |||
2900 | enodev: | ||
2901 | sbridge_printk(KERN_ERR, "Some needed devices are missing\n"); | ||
2902 | return -ENODEV; | ||
2903 | } | ||
2904 | |||
2041 | /**************************************************************************** | 2905 | /**************************************************************************** |
2042 | Error check routines | 2906 | Error check routines |
2043 | ****************************************************************************/ | 2907 | ****************************************************************************/ |
@@ -2127,8 +2991,36 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, | |||
2127 | if (!GET_BITFIELD(m->status, 58, 58)) | 2991 | if (!GET_BITFIELD(m->status, 58, 58)) |
2128 | return; | 2992 | return; |
2129 | 2993 | ||
2130 | rc = get_memory_error_data(mci, m->addr, &socket, &ha, | 2994 | if (pvt->info.type == KNIGHTS_LANDING) { |
2131 | &channel_mask, &rank, &area_type, msg); | 2995 | if (channel == 14) { |
2996 | edac_dbg(0, "%s%s err_code:%04x:%04x EDRAM bank %d\n", | ||
2997 | overflow ? " OVERFLOW" : "", | ||
2998 | (uncorrected_error && recoverable) | ||
2999 | ? " recoverable" : "", | ||
3000 | mscod, errcode, | ||
3001 | m->bank); | ||
3002 | } else { | ||
3003 | char A = *("A"); | ||
3004 | |||
3005 | channel = knl_channel_remap(channel); | ||
3006 | channel_mask = 1 << channel; | ||
3007 | snprintf(msg, sizeof(msg), | ||
3008 | "%s%s err_code:%04x:%04x channel:%d (DIMM_%c)", | ||
3009 | overflow ? " OVERFLOW" : "", | ||
3010 | (uncorrected_error && recoverable) | ||
3011 | ? " recoverable" : " ", | ||
3012 | mscod, errcode, channel, A + channel); | ||
3013 | edac_mc_handle_error(tp_event, mci, core_err_cnt, | ||
3014 | m->addr >> PAGE_SHIFT, m->addr & ~PAGE_MASK, 0, | ||
3015 | channel, 0, -1, | ||
3016 | optype, msg); | ||
3017 | } | ||
3018 | return; | ||
3019 | } else { | ||
3020 | rc = get_memory_error_data(mci, m->addr, &socket, &ha, | ||
3021 | &channel_mask, &rank, &area_type, msg); | ||
3022 | } | ||
3023 | |||
2132 | if (rc < 0) | 3024 | if (rc < 0) |
2133 | goto err_parsing; | 3025 | goto err_parsing; |
2134 | new_mci = get_mci_for_node_id(socket); | 3026 | new_mci = get_mci_for_node_id(socket); |
@@ -2359,10 +3251,11 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) | |||
2359 | 3251 | ||
2360 | /* allocate a new MC control structure */ | 3252 | /* allocate a new MC control structure */ |
2361 | layers[0].type = EDAC_MC_LAYER_CHANNEL; | 3253 | layers[0].type = EDAC_MC_LAYER_CHANNEL; |
2362 | layers[0].size = NUM_CHANNELS; | 3254 | layers[0].size = type == KNIGHTS_LANDING ? |
3255 | KNL_MAX_CHANNELS : NUM_CHANNELS; | ||
2363 | layers[0].is_virt_csrow = false; | 3256 | layers[0].is_virt_csrow = false; |
2364 | layers[1].type = EDAC_MC_LAYER_SLOT; | 3257 | layers[1].type = EDAC_MC_LAYER_SLOT; |
2365 | layers[1].size = MAX_DIMMS; | 3258 | layers[1].size = type == KNIGHTS_LANDING ? 1 : MAX_DIMMS; |
2366 | layers[1].is_virt_csrow = true; | 3259 | layers[1].is_virt_csrow = true; |
2367 | mci = edac_mc_alloc(sbridge_dev->mc, ARRAY_SIZE(layers), layers, | 3260 | mci = edac_mc_alloc(sbridge_dev->mc, ARRAY_SIZE(layers), layers, |
2368 | sizeof(*pvt)); | 3261 | sizeof(*pvt)); |
@@ -2380,7 +3273,8 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) | |||
2380 | pvt->sbridge_dev = sbridge_dev; | 3273 | pvt->sbridge_dev = sbridge_dev; |
2381 | sbridge_dev->mci = mci; | 3274 | sbridge_dev->mci = mci; |
2382 | 3275 | ||
2383 | mci->mtype_cap = MEM_FLAG_DDR3; | 3276 | mci->mtype_cap = type == KNIGHTS_LANDING ? |
3277 | MEM_FLAG_DDR4 : MEM_FLAG_DDR3; | ||
2384 | mci->edac_ctl_cap = EDAC_FLAG_NONE; | 3278 | mci->edac_ctl_cap = EDAC_FLAG_NONE; |
2385 | mci->edac_cap = EDAC_FLAG_NONE; | 3279 | mci->edac_cap = EDAC_FLAG_NONE; |
2386 | mci->mod_name = "sbridge_edac.c"; | 3280 | mci->mod_name = "sbridge_edac.c"; |
@@ -2401,6 +3295,10 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) | |||
2401 | pvt->info.get_memory_type = get_memory_type; | 3295 | pvt->info.get_memory_type = get_memory_type; |
2402 | pvt->info.get_node_id = get_node_id; | 3296 | pvt->info.get_node_id = get_node_id; |
2403 | pvt->info.rir_limit = rir_limit; | 3297 | pvt->info.rir_limit = rir_limit; |
3298 | pvt->info.sad_limit = sad_limit; | ||
3299 | pvt->info.interleave_mode = interleave_mode; | ||
3300 | pvt->info.show_interleave_mode = show_interleave_mode; | ||
3301 | pvt->info.dram_attr = dram_attr; | ||
2404 | pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule); | 3302 | pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule); |
2405 | pvt->info.interleave_list = ibridge_interleave_list; | 3303 | pvt->info.interleave_list = ibridge_interleave_list; |
2406 | pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); | 3304 | pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); |
@@ -2421,6 +3319,10 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) | |||
2421 | pvt->info.get_memory_type = get_memory_type; | 3319 | pvt->info.get_memory_type = get_memory_type; |
2422 | pvt->info.get_node_id = get_node_id; | 3320 | pvt->info.get_node_id = get_node_id; |
2423 | pvt->info.rir_limit = rir_limit; | 3321 | pvt->info.rir_limit = rir_limit; |
3322 | pvt->info.sad_limit = sad_limit; | ||
3323 | pvt->info.interleave_mode = interleave_mode; | ||
3324 | pvt->info.show_interleave_mode = show_interleave_mode; | ||
3325 | pvt->info.dram_attr = dram_attr; | ||
2424 | pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule); | 3326 | pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule); |
2425 | pvt->info.interleave_list = sbridge_interleave_list; | 3327 | pvt->info.interleave_list = sbridge_interleave_list; |
2426 | pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list); | 3328 | pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list); |
@@ -2441,6 +3343,10 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) | |||
2441 | pvt->info.get_memory_type = haswell_get_memory_type; | 3343 | pvt->info.get_memory_type = haswell_get_memory_type; |
2442 | pvt->info.get_node_id = haswell_get_node_id; | 3344 | pvt->info.get_node_id = haswell_get_node_id; |
2443 | pvt->info.rir_limit = haswell_rir_limit; | 3345 | pvt->info.rir_limit = haswell_rir_limit; |
3346 | pvt->info.sad_limit = sad_limit; | ||
3347 | pvt->info.interleave_mode = interleave_mode; | ||
3348 | pvt->info.show_interleave_mode = show_interleave_mode; | ||
3349 | pvt->info.dram_attr = dram_attr; | ||
2444 | pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule); | 3350 | pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule); |
2445 | pvt->info.interleave_list = ibridge_interleave_list; | 3351 | pvt->info.interleave_list = ibridge_interleave_list; |
2446 | pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); | 3352 | pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); |
@@ -2461,6 +3367,10 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) | |||
2461 | pvt->info.get_memory_type = haswell_get_memory_type; | 3367 | pvt->info.get_memory_type = haswell_get_memory_type; |
2462 | pvt->info.get_node_id = haswell_get_node_id; | 3368 | pvt->info.get_node_id = haswell_get_node_id; |
2463 | pvt->info.rir_limit = haswell_rir_limit; | 3369 | pvt->info.rir_limit = haswell_rir_limit; |
3370 | pvt->info.sad_limit = sad_limit; | ||
3371 | pvt->info.interleave_mode = interleave_mode; | ||
3372 | pvt->info.show_interleave_mode = show_interleave_mode; | ||
3373 | pvt->info.dram_attr = dram_attr; | ||
2464 | pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule); | 3374 | pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule); |
2465 | pvt->info.interleave_list = ibridge_interleave_list; | 3375 | pvt->info.interleave_list = ibridge_interleave_list; |
2466 | pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); | 3376 | pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); |
@@ -2473,6 +3383,30 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) | |||
2473 | if (unlikely(rc < 0)) | 3383 | if (unlikely(rc < 0)) |
2474 | goto fail0; | 3384 | goto fail0; |
2475 | break; | 3385 | break; |
3386 | case KNIGHTS_LANDING: | ||
3387 | /* pvt->info.rankcfgr == ??? */ | ||
3388 | pvt->info.get_tolm = knl_get_tolm; | ||
3389 | pvt->info.get_tohm = knl_get_tohm; | ||
3390 | pvt->info.dram_rule = knl_dram_rule; | ||
3391 | pvt->info.get_memory_type = knl_get_memory_type; | ||
3392 | pvt->info.get_node_id = knl_get_node_id; | ||
3393 | pvt->info.rir_limit = NULL; | ||
3394 | pvt->info.sad_limit = knl_sad_limit; | ||
3395 | pvt->info.interleave_mode = knl_interleave_mode; | ||
3396 | pvt->info.show_interleave_mode = knl_show_interleave_mode; | ||
3397 | pvt->info.dram_attr = dram_attr_knl; | ||
3398 | pvt->info.max_sad = ARRAY_SIZE(knl_dram_rule); | ||
3399 | pvt->info.interleave_list = knl_interleave_list; | ||
3400 | pvt->info.max_interleave = ARRAY_SIZE(knl_interleave_list); | ||
3401 | pvt->info.interleave_pkg = ibridge_interleave_pkg; | ||
3402 | pvt->info.get_width = knl_get_width; | ||
3403 | mci->ctl_name = kasprintf(GFP_KERNEL, | ||
3404 | "Knights Landing Socket#%d", mci->mc_idx); | ||
3405 | |||
3406 | rc = knl_mci_bind_devs(mci, sbridge_dev); | ||
3407 | if (unlikely(rc < 0)) | ||
3408 | goto fail0; | ||
3409 | break; | ||
2476 | } | 3410 | } |
2477 | 3411 | ||
2478 | /* Get dimm basic config and the memory layout */ | 3412 | /* Get dimm basic config and the memory layout */ |
@@ -2527,20 +3461,29 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
2527 | 3461 | ||
2528 | switch (pdev->device) { | 3462 | switch (pdev->device) { |
2529 | case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA: | 3463 | case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA: |
2530 | rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_ibridge_table); | 3464 | rc = sbridge_get_all_devices(&num_mc, |
3465 | pci_dev_descr_ibridge_table); | ||
2531 | type = IVY_BRIDGE; | 3466 | type = IVY_BRIDGE; |
2532 | break; | 3467 | break; |
2533 | case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0: | 3468 | case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0: |
2534 | rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_sbridge_table); | 3469 | rc = sbridge_get_all_devices(&num_mc, |
3470 | pci_dev_descr_sbridge_table); | ||
2535 | type = SANDY_BRIDGE; | 3471 | type = SANDY_BRIDGE; |
2536 | break; | 3472 | break; |
2537 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0: | 3473 | case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0: |
2538 | rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_haswell_table); | 3474 | rc = sbridge_get_all_devices(&num_mc, |
3475 | pci_dev_descr_haswell_table); | ||
2539 | type = HASWELL; | 3476 | type = HASWELL; |
2540 | break; | 3477 | break; |
2541 | case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0: | 3478 | case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0: |
2542 | rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_broadwell_table); | 3479 | rc = sbridge_get_all_devices(&num_mc, |
3480 | pci_dev_descr_broadwell_table); | ||
2543 | type = BROADWELL; | 3481 | type = BROADWELL; |
3482 | break; | ||
3483 | case PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0: | ||
3484 | rc = sbridge_get_all_devices_knl(&num_mc, | ||
3485 | pci_dev_descr_knl_table); | ||
3486 | type = KNIGHTS_LANDING; | ||
2544 | break; | 3487 | break; |
2545 | } | 3488 | } |
2546 | if (unlikely(rc < 0)) { | 3489 | if (unlikely(rc < 0)) { |
diff --git a/drivers/edac/wq.c b/drivers/edac/wq.c new file mode 100644 index 000000000000..1b8c07e44fd8 --- /dev/null +++ b/drivers/edac/wq.c | |||
@@ -0,0 +1,42 @@ | |||
1 | #include "edac_module.h" | ||
2 | |||
3 | static struct workqueue_struct *wq; | ||
4 | |||
5 | bool edac_queue_work(struct delayed_work *work, unsigned long delay) | ||
6 | { | ||
7 | return queue_delayed_work(wq, work, delay); | ||
8 | } | ||
9 | EXPORT_SYMBOL_GPL(edac_queue_work); | ||
10 | |||
11 | bool edac_mod_work(struct delayed_work *work, unsigned long delay) | ||
12 | { | ||
13 | return mod_delayed_work(wq, work, delay); | ||
14 | } | ||
15 | EXPORT_SYMBOL_GPL(edac_mod_work); | ||
16 | |||
17 | bool edac_stop_work(struct delayed_work *work) | ||
18 | { | ||
19 | bool ret; | ||
20 | |||
21 | ret = cancel_delayed_work_sync(work); | ||
22 | flush_workqueue(wq); | ||
23 | |||
24 | return ret; | ||
25 | } | ||
26 | EXPORT_SYMBOL_GPL(edac_stop_work); | ||
27 | |||
28 | int edac_workqueue_setup(void) | ||
29 | { | ||
30 | wq = create_singlethread_workqueue("edac-poller"); | ||
31 | if (!wq) | ||
32 | return -ENODEV; | ||
33 | else | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | void edac_workqueue_teardown(void) | ||
38 | { | ||
39 | flush_workqueue(wq); | ||
40 | destroy_workqueue(wq); | ||
41 | wq = NULL; | ||
42 | } | ||
diff --git a/include/linux/edac.h b/include/linux/edac.h index 4fe67b853de0..9e0d78966552 100644 --- a/include/linux/edac.h +++ b/include/linux/edac.h | |||
@@ -28,12 +28,10 @@ struct device; | |||
28 | extern int edac_op_state; | 28 | extern int edac_op_state; |
29 | extern int edac_err_assert; | 29 | extern int edac_err_assert; |
30 | extern atomic_t edac_handlers; | 30 | extern atomic_t edac_handlers; |
31 | extern struct bus_type edac_subsys; | ||
32 | 31 | ||
33 | extern int edac_handler_set(void); | 32 | extern int edac_handler_set(void); |
34 | extern void edac_atomic_assert_error(void); | 33 | extern void edac_atomic_assert_error(void); |
35 | extern struct bus_type *edac_get_sysfs_subsys(void); | 34 | extern struct bus_type *edac_get_sysfs_subsys(void); |
36 | extern void edac_put_sysfs_subsys(void); | ||
37 | 35 | ||
38 | enum { | 36 | enum { |
39 | EDAC_REPORTING_ENABLED, | 37 | EDAC_REPORTING_ENABLED, |
@@ -237,8 +235,10 @@ enum mem_type { | |||
237 | #define MEM_FLAG_FB_DDR2 BIT(MEM_FB_DDR2) | 235 | #define MEM_FLAG_FB_DDR2 BIT(MEM_FB_DDR2) |
238 | #define MEM_FLAG_RDDR2 BIT(MEM_RDDR2) | 236 | #define MEM_FLAG_RDDR2 BIT(MEM_RDDR2) |
239 | #define MEM_FLAG_XDR BIT(MEM_XDR) | 237 | #define MEM_FLAG_XDR BIT(MEM_XDR) |
240 | #define MEM_FLAG_DDR3 BIT(MEM_DDR3) | 238 | #define MEM_FLAG_DDR3 BIT(MEM_DDR3) |
241 | #define MEM_FLAG_RDDR3 BIT(MEM_RDDR3) | 239 | #define MEM_FLAG_RDDR3 BIT(MEM_RDDR3) |
240 | #define MEM_FLAG_DDR4 BIT(MEM_DDR4) | ||
241 | #define MEM_FLAG_RDDR4 BIT(MEM_RDDR4) | ||
242 | 242 | ||
243 | /** | 243 | /** |
244 | * enum edac-type - Error Detection and Correction capabilities and mode | 244 | * enum edac-type - Error Detection and Correction capabilities and mode |
diff --git a/include/linux/fsl/edac.h b/include/linux/fsl/edac.h new file mode 100644 index 000000000000..90d64d4ec1a9 --- /dev/null +++ b/include/linux/fsl/edac.h | |||
@@ -0,0 +1,8 @@ | |||
1 | #ifndef FSL_EDAC_H | ||
2 | #define FSL_EDAC_H | ||
3 | |||
4 | struct mpc85xx_edac_pci_plat_data { | ||
5 | struct device_node *of_node; | ||
6 | }; | ||
7 | |||
8 | #endif | ||