diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-04 15:06:26 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-04 15:06:26 -0400 |
commit | 19fe416532f798e199f04d25816b1bd36e48d6fe (patch) | |
tree | a3fcda5b75284550224782d746290a3c0b88c126 | |
parent | 58e4411b2d05bea9992fd8ee510f696b73d314c1 (diff) | |
parent | a29d64a45eed1ee0d4ac90335da79ad1a9a0990d (diff) |
Merge tag 'edac_for_4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp
Pull EDAC updates from Borislav Petkov:
"A lot of movement in the EDAC tree this time around, coarse summary
below:
- Altera Arria10 enablement of NAND, DMA, USB, QSPI and SD-MMC FIFO
buffers (Thor Thayer)
- split the memory controller part out of mpc85xx and share it with a
new Freescale ARM Layerscape driver (York Sun)
- amd64_edac fixes (Yazen Ghannam)
- misc cleanups, refactoring and fixes all over the place"
* tag 'edac_for_4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp: (37 commits)
EDAC, altera: Add IRQ Flags to disable IRQ while handling
EDAC, altera: Correct EDAC IRQ error message
EDAC, amd64: Autoload module using x86_cpu_id
EDAC, sb_edac: Remove NULL pointer check on array pci_tad
EDAC: Remove NO_IRQ from powerpc-only drivers
EDAC, fsl_ddr: Fix error return code in fsl_mc_err_probe()
EDAC, fsl_ddr: Add entry to MAINTAINERS
EDAC: Move Doug Thompson to CREDITS
EDAC, I3000: Orphan driver
EDAC, fsl_ddr: Replace simple_strtoul() with kstrtoul()
EDAC, layerscape: Add Layerscape EDAC support
EDAC, fsl_ddr: Fix IRQ dispose warning when module is removed
EDAC, fsl_ddr: Add support for little endian
EDAC, fsl_ddr: Add missing DDR DRAM types
EDAC, fsl_ddr: Rename macros and names
EDAC, fsl-ddr: Separate FSL DDR driver from MPC85xx
EDAC, mpc85xx: Replace printk() with pr_* format
EDAC, mpc85xx: Drop setting/clearing RFXE bit in HID1
EDAC, altera: Rename MC trigger to common name
EDAC, altera: Rename device trigger to common name
...
-rw-r--r-- | CREDITS | 8 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt | 98 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/memory-controllers/fsl/ddr.txt (renamed from Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt) | 2 | ||||
-rw-r--r-- | MAINTAINERS | 15 | ||||
-rw-r--r-- | arch/arm/boot/dts/socfpga_arria10.dtsi | 16 | ||||
-rw-r--r-- | arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts | 12 | ||||
-rw-r--r-- | arch/arm64/Kconfig.platforms | 1 | ||||
-rw-r--r-- | drivers/edac/Kconfig | 42 | ||||
-rw-r--r-- | drivers/edac/Makefile | 8 | ||||
-rw-r--r-- | drivers/edac/altera_edac.c | 346 | ||||
-rw-r--r-- | drivers/edac/altera_edac.h | 6 | ||||
-rw-r--r-- | drivers/edac/amd64_edac.c | 24 | ||||
-rw-r--r-- | drivers/edac/fsl_ddr_edac.c | 633 | ||||
-rw-r--r-- | drivers/edac/fsl_ddr_edac.h | 79 | ||||
-rw-r--r-- | drivers/edac/layerscape_edac.c | 73 | ||||
-rw-r--r-- | drivers/edac/mpc85xx_edac.c | 685 | ||||
-rw-r--r-- | drivers/edac/mpc85xx_edac.h | 66 | ||||
-rw-r--r-- | drivers/edac/mv64x60_edac.c | 4 | ||||
-rw-r--r-- | drivers/edac/ppc4xx_edac.c | 4 | ||||
-rw-r--r-- | drivers/edac/sb_edac.c | 5 | ||||
-rw-r--r-- | drivers/edac/wq.c | 2 |
21 files changed, 1373 insertions, 756 deletions
@@ -3523,6 +3523,10 @@ S: 145 Howard St. | |||
3523 | S: Northborough, MA 01532 | 3523 | S: Northborough, MA 01532 |
3524 | S: USA | 3524 | S: USA |
3525 | 3525 | ||
3526 | N: Doug Thompson | ||
3527 | E: dougthompson@xmission.com | ||
3528 | D: EDAC | ||
3529 | |||
3526 | N: Tommy Thorn | 3530 | N: Tommy Thorn |
3527 | E: Tommy.Thorn@irisa.fr | 3531 | E: Tommy.Thorn@irisa.fr |
3528 | W: http://www.irisa.fr/prive/thorn/index.html | 3532 | W: http://www.irisa.fr/prive/thorn/index.html |
@@ -3659,6 +3663,10 @@ S: Obere Heerbergstrasse 17 | |||
3659 | S: 97078 Wuerzburg | 3663 | S: 97078 Wuerzburg |
3660 | S: Germany | 3664 | S: Germany |
3661 | 3665 | ||
3666 | N: Jason Uhlenkott | ||
3667 | E: juhlenko@akamai.com | ||
3668 | D: I3000 EDAC driver | ||
3669 | |||
3662 | N: Greg Ungerer | 3670 | N: Greg Ungerer |
3663 | E: gerg@snapgear.com | 3671 | E: gerg@snapgear.com |
3664 | D: uClinux kernel hacker | 3672 | D: uClinux kernel hacker |
diff --git a/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt b/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt index b545856a444f..4a1714f96bab 100644 --- a/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt +++ b/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt | |||
@@ -90,6 +90,47 @@ Required Properties: | |||
90 | - interrupts : Should be single bit error interrupt, then double bit error | 90 | - interrupts : Should be single bit error interrupt, then double bit error |
91 | interrupt, in this order. | 91 | interrupt, in this order. |
92 | 92 | ||
93 | NAND FIFO ECC | ||
94 | Required Properties: | ||
95 | - compatible : Should be "altr,socfpga-nand-ecc" | ||
96 | - reg : Address and size for ECC block registers. | ||
97 | - altr,ecc-parent : phandle to parent NAND node. | ||
98 | - interrupts : Should be single bit error interrupt, then double bit error | ||
99 | interrupt, in this order. | ||
100 | |||
101 | DMA FIFO ECC | ||
102 | Required Properties: | ||
103 | - compatible : Should be "altr,socfpga-dma-ecc" | ||
104 | - reg : Address and size for ECC block registers. | ||
105 | - altr,ecc-parent : phandle to parent DMA node. | ||
106 | - interrupts : Should be single bit error interrupt, then double bit error | ||
107 | interrupt, in this order. | ||
108 | |||
109 | USB FIFO ECC | ||
110 | Required Properties: | ||
111 | - compatible : Should be "altr,socfpga-usb-ecc" | ||
112 | - reg : Address and size for ECC block registers. | ||
113 | - altr,ecc-parent : phandle to parent USB node. | ||
114 | - interrupts : Should be single bit error interrupt, then double bit error | ||
115 | interrupt, in this order. | ||
116 | |||
117 | QSPI FIFO ECC | ||
118 | Required Properties: | ||
119 | - compatible : Should be "altr,socfpga-qspi-ecc" | ||
120 | - reg : Address and size for ECC block registers. | ||
121 | - altr,ecc-parent : phandle to parent QSPI node. | ||
122 | - interrupts : Should be single bit error interrupt, then double bit error | ||
123 | interrupt, in this order. | ||
124 | |||
125 | SDMMC FIFO ECC | ||
126 | Required Properties: | ||
127 | - compatible : Should be "altr,socfpga-sdmmc-ecc" | ||
128 | - reg : Address and size for ECC block registers. | ||
129 | - altr,ecc-parent : phandle to parent SD/MMC node. | ||
130 | - interrupts : Should be single bit error interrupt, then double bit error | ||
131 | interrupt, in this order for port A, and then single bit error interrupt, | ||
132 | then double bit error interrupt in this order for port B. | ||
133 | |||
93 | Example: | 134 | Example: |
94 | 135 | ||
95 | eccmgr: eccmgr@ffd06000 { | 136 | eccmgr: eccmgr@ffd06000 { |
@@ -132,4 +173,61 @@ Example: | |||
132 | interrupts = <5 IRQ_TYPE_LEVEL_HIGH>, | 173 | interrupts = <5 IRQ_TYPE_LEVEL_HIGH>, |
133 | <37 IRQ_TYPE_LEVEL_HIGH>; | 174 | <37 IRQ_TYPE_LEVEL_HIGH>; |
134 | }; | 175 | }; |
176 | |||
177 | nand-buf-ecc@ff8c2000 { | ||
178 | compatible = "altr,socfpga-nand-ecc"; | ||
179 | reg = <0xff8c2000 0x400>; | ||
180 | altr,ecc-parent = <&nand>; | ||
181 | interrupts = <11 IRQ_TYPE_LEVEL_HIGH>, | ||
182 | <43 IRQ_TYPE_LEVEL_HIGH>; | ||
183 | }; | ||
184 | |||
185 | nand-rd-ecc@ff8c2400 { | ||
186 | compatible = "altr,socfpga-nand-ecc"; | ||
187 | reg = <0xff8c2400 0x400>; | ||
188 | altr,ecc-parent = <&nand>; | ||
189 | interrupts = <13 IRQ_TYPE_LEVEL_HIGH>, | ||
190 | <45 IRQ_TYPE_LEVEL_HIGH>; | ||
191 | }; | ||
192 | |||
193 | nand-wr-ecc@ff8c2800 { | ||
194 | compatible = "altr,socfpga-nand-ecc"; | ||
195 | reg = <0xff8c2800 0x400>; | ||
196 | altr,ecc-parent = <&nand>; | ||
197 | interrupts = <12 IRQ_TYPE_LEVEL_HIGH>, | ||
198 | <44 IRQ_TYPE_LEVEL_HIGH>; | ||
199 | }; | ||
200 | |||
201 | dma-ecc@ff8c8000 { | ||
202 | compatible = "altr,socfpga-dma-ecc"; | ||
203 | reg = <0xff8c8000 0x400>; | ||
204 | altr,ecc-parent = <&pdma>; | ||
205 | interrupts = <10 IRQ_TYPE_LEVEL_HIGH>, | ||
206 | <42 IRQ_TYPE_LEVEL_HIGH>; | ||
207 | |||
208 | usb0-ecc@ff8c8800 { | ||
209 | compatible = "altr,socfpga-usb-ecc"; | ||
210 | reg = <0xff8c8800 0x400>; | ||
211 | altr,ecc-parent = <&usb0>; | ||
212 | interrupts = <2 IRQ_TYPE_LEVEL_HIGH>, | ||
213 | <34 IRQ_TYPE_LEVEL_HIGH>; | ||
214 | }; | ||
215 | |||
216 | qspi-ecc@ff8c8400 { | ||
217 | compatible = "altr,socfpga-qspi-ecc"; | ||
218 | reg = <0xff8c8400 0x400>; | ||
219 | altr,ecc-parent = <&qspi>; | ||
220 | interrupts = <14 IRQ_TYPE_LEVEL_HIGH>, | ||
221 | <46 IRQ_TYPE_LEVEL_HIGH>; | ||
222 | }; | ||
223 | |||
224 | sdmmc-ecc@ff8c2c00 { | ||
225 | compatible = "altr,socfpga-sdmmc-ecc"; | ||
226 | reg = <0xff8c2c00 0x400>; | ||
227 | altr,ecc-parent = <&mmc>; | ||
228 | interrupts = <15 IRQ_TYPE_LEVEL_HIGH>, | ||
229 | <47 IRQ_TYPE_LEVEL_HIGH>, | ||
230 | <16 IRQ_TYPE_LEVEL_HIGH>, | ||
231 | <48 IRQ_TYPE_LEVEL_HIGH>; | ||
232 | }; | ||
135 | }; | 233 | }; |
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt b/Documentation/devicetree/bindings/memory-controllers/fsl/ddr.txt index f87856faf1ab..dde6d837083a 100644 --- a/Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt +++ b/Documentation/devicetree/bindings/memory-controllers/fsl/ddr.txt | |||
@@ -7,6 +7,8 @@ Properties: | |||
7 | "fsl,qoriq-memory-controller". | 7 | "fsl,qoriq-memory-controller". |
8 | - reg : Address and size of DDR controller registers | 8 | - reg : Address and size of DDR controller registers |
9 | - interrupts : Error interrupt of DDR controller | 9 | - interrupts : Error interrupt of DDR controller |
10 | - little-endian : Specifies little-endian access to registers | ||
11 | If omitted, big-endian will be used. | ||
10 | 12 | ||
11 | Example 1: | 13 | Example 1: |
12 | 14 | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 49a5798f4290..f6c346684346 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -4410,7 +4410,6 @@ F: Documentation/filesystems/ecryptfs.txt | |||
4410 | F: fs/ecryptfs/ | 4410 | F: fs/ecryptfs/ |
4411 | 4411 | ||
4412 | EDAC-CORE | 4412 | EDAC-CORE |
4413 | M: Doug Thompson <dougthompson@xmission.com> | ||
4414 | M: Borislav Petkov <bp@alien8.de> | 4413 | M: Borislav Petkov <bp@alien8.de> |
4415 | M: Mauro Carvalho Chehab <mchehab@s-opensource.com> | 4414 | M: Mauro Carvalho Chehab <mchehab@s-opensource.com> |
4416 | M: Mauro Carvalho Chehab <mchehab@kernel.org> | 4415 | M: Mauro Carvalho Chehab <mchehab@kernel.org> |
@@ -4423,14 +4422,12 @@ F: drivers/edac/ | |||
4423 | F: include/linux/edac.h | 4422 | F: include/linux/edac.h |
4424 | 4423 | ||
4425 | EDAC-AMD64 | 4424 | EDAC-AMD64 |
4426 | M: Doug Thompson <dougthompson@xmission.com> | ||
4427 | M: Borislav Petkov <bp@alien8.de> | 4425 | M: Borislav Petkov <bp@alien8.de> |
4428 | L: linux-edac@vger.kernel.org | 4426 | L: linux-edac@vger.kernel.org |
4429 | S: Maintained | 4427 | S: Maintained |
4430 | F: drivers/edac/amd64_edac* | 4428 | F: drivers/edac/amd64_edac* |
4431 | 4429 | ||
4432 | EDAC-CALXEDA | 4430 | EDAC-CALXEDA |
4433 | M: Doug Thompson <dougthompson@xmission.com> | ||
4434 | M: Robert Richter <rric@kernel.org> | 4431 | M: Robert Richter <rric@kernel.org> |
4435 | L: linux-edac@vger.kernel.org | 4432 | L: linux-edac@vger.kernel.org |
4436 | S: Maintained | 4433 | S: Maintained |
@@ -4446,17 +4443,21 @@ F: drivers/edac/octeon_edac* | |||
4446 | 4443 | ||
4447 | EDAC-E752X | 4444 | EDAC-E752X |
4448 | M: Mark Gross <mark.gross@intel.com> | 4445 | M: Mark Gross <mark.gross@intel.com> |
4449 | M: Doug Thompson <dougthompson@xmission.com> | ||
4450 | L: linux-edac@vger.kernel.org | 4446 | L: linux-edac@vger.kernel.org |
4451 | S: Maintained | 4447 | S: Maintained |
4452 | F: drivers/edac/e752x_edac.c | 4448 | F: drivers/edac/e752x_edac.c |
4453 | 4449 | ||
4454 | EDAC-E7XXX | 4450 | EDAC-E7XXX |
4455 | M: Doug Thompson <dougthompson@xmission.com> | ||
4456 | L: linux-edac@vger.kernel.org | 4451 | L: linux-edac@vger.kernel.org |
4457 | S: Maintained | 4452 | S: Maintained |
4458 | F: drivers/edac/e7xxx_edac.c | 4453 | F: drivers/edac/e7xxx_edac.c |
4459 | 4454 | ||
4455 | EDAC-FSL_DDR | ||
4456 | M: York Sun <york.sun@nxp.com> | ||
4457 | L: linux-edac@vger.kernel.org | ||
4458 | S: Maintained | ||
4459 | F: drivers/edac/fsl_ddr_edac.* | ||
4460 | |||
4460 | EDAC-GHES | 4461 | EDAC-GHES |
4461 | M: Mauro Carvalho Chehab <mchehab@s-opensource.com> | 4462 | M: Mauro Carvalho Chehab <mchehab@s-opensource.com> |
4462 | M: Mauro Carvalho Chehab <mchehab@kernel.org> | 4463 | M: Mauro Carvalho Chehab <mchehab@kernel.org> |
@@ -4471,13 +4472,11 @@ S: Maintained | |||
4471 | F: drivers/edac/i82443bxgx_edac.c | 4472 | F: drivers/edac/i82443bxgx_edac.c |
4472 | 4473 | ||
4473 | EDAC-I3000 | 4474 | EDAC-I3000 |
4474 | M: Jason Uhlenkott <juhlenko@akamai.com> | ||
4475 | L: linux-edac@vger.kernel.org | 4475 | L: linux-edac@vger.kernel.org |
4476 | S: Maintained | 4476 | S: Orphan |
4477 | F: drivers/edac/i3000_edac.c | 4477 | F: drivers/edac/i3000_edac.c |
4478 | 4478 | ||
4479 | EDAC-I5000 | 4479 | EDAC-I5000 |
4480 | M: Doug Thompson <dougthompson@xmission.com> | ||
4481 | L: linux-edac@vger.kernel.org | 4480 | L: linux-edac@vger.kernel.org |
4482 | S: Maintained | 4481 | S: Maintained |
4483 | F: drivers/edac/i5000_edac.c | 4482 | F: drivers/edac/i5000_edac.c |
diff --git a/arch/arm/boot/dts/socfpga_arria10.dtsi b/arch/arm/boot/dts/socfpga_arria10.dtsi index 94000cbe576b..f520cbff5e1c 100644 --- a/arch/arm/boot/dts/socfpga_arria10.dtsi +++ b/arch/arm/boot/dts/socfpga_arria10.dtsi | |||
@@ -639,6 +639,22 @@ | |||
639 | interrupts = <5 IRQ_TYPE_LEVEL_HIGH>, | 639 | interrupts = <5 IRQ_TYPE_LEVEL_HIGH>, |
640 | <37 IRQ_TYPE_LEVEL_HIGH>; | 640 | <37 IRQ_TYPE_LEVEL_HIGH>; |
641 | }; | 641 | }; |
642 | |||
643 | dma-ecc@ff8c8000 { | ||
644 | compatible = "altr,socfpga-dma-ecc"; | ||
645 | reg = <0xff8c8000 0x400>; | ||
646 | altr,ecc-parent = <&pdma>; | ||
647 | interrupts = <10 IRQ_TYPE_LEVEL_HIGH>, | ||
648 | <42 IRQ_TYPE_LEVEL_HIGH>; | ||
649 | }; | ||
650 | |||
651 | usb0-ecc@ff8c8800 { | ||
652 | compatible = "altr,socfpga-usb-ecc"; | ||
653 | reg = <0xff8c8800 0x400>; | ||
654 | altr,ecc-parent = <&usb0>; | ||
655 | interrupts = <2 IRQ_TYPE_LEVEL_HIGH>, | ||
656 | <34 IRQ_TYPE_LEVEL_HIGH>; | ||
657 | }; | ||
642 | }; | 658 | }; |
643 | 659 | ||
644 | rst: rstmgr@ffd05000 { | 660 | rst: rstmgr@ffd05000 { |
diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts index 8a7dfa473e98..040a164ba148 100644 --- a/arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts +++ b/arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts | |||
@@ -25,3 +25,15 @@ | |||
25 | broken-cd; | 25 | broken-cd; |
26 | bus-width = <4>; | 26 | bus-width = <4>; |
27 | }; | 27 | }; |
28 | |||
29 | &eccmgr { | ||
30 | sdmmca-ecc@ff8c2c00 { | ||
31 | compatible = "altr,socfpga-sdmmc-ecc"; | ||
32 | reg = <0xff8c2c00 0x400>; | ||
33 | altr,ecc-parent = <&mmc>; | ||
34 | interrupts = <15 IRQ_TYPE_LEVEL_HIGH>, | ||
35 | <47 IRQ_TYPE_LEVEL_HIGH>, | ||
36 | <16 IRQ_TYPE_LEVEL_HIGH>, | ||
37 | <48 IRQ_TYPE_LEVEL_HIGH>; | ||
38 | }; | ||
39 | }; | ||
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index a8c77c72a831..96ef543f6bd8 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms | |||
@@ -55,6 +55,7 @@ config ARCH_EXYNOS | |||
55 | 55 | ||
56 | config ARCH_LAYERSCAPE | 56 | config ARCH_LAYERSCAPE |
57 | bool "ARMv8 based Freescale Layerscape SoC family" | 57 | bool "ARMv8 based Freescale Layerscape SoC family" |
58 | select EDAC_SUPPORT | ||
58 | help | 59 | help |
59 | This enables support for the Freescale Layerscape SoC family. | 60 | This enables support for the Freescale Layerscape SoC family. |
60 | 61 | ||
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index dff1a4a6dc1b..82d85cce81f8 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig | |||
@@ -266,6 +266,13 @@ config EDAC_MPC85XX | |||
266 | Support for error detection and correction on the Freescale | 266 | Support for error detection and correction on the Freescale |
267 | MPC8349, MPC8560, MPC8540, MPC8548, T4240 | 267 | MPC8349, MPC8560, MPC8540, MPC8548, T4240 |
268 | 268 | ||
269 | config EDAC_LAYERSCAPE | ||
270 | tristate "Freescale Layerscape DDR" | ||
271 | depends on EDAC_MM_EDAC && ARCH_LAYERSCAPE | ||
272 | help | ||
273 | Support for error detection and correction on Freescale memory | ||
274 | controllers on Layerscape SoCs. | ||
275 | |||
269 | config EDAC_MV64X60 | 276 | config EDAC_MV64X60 |
270 | tristate "Marvell MV64x60" | 277 | tristate "Marvell MV64x60" |
271 | depends on EDAC_MM_EDAC && MV64X60 | 278 | depends on EDAC_MM_EDAC && MV64X60 |
@@ -406,6 +413,41 @@ config EDAC_ALTERA_ETHERNET | |||
406 | Support for error detection and correction on the | 413 | Support for error detection and correction on the |
407 | Altera Ethernet FIFO Memory for Altera SoCs. | 414 | Altera Ethernet FIFO Memory for Altera SoCs. |
408 | 415 | ||
416 | config EDAC_ALTERA_NAND | ||
417 | bool "Altera NAND FIFO ECC" | ||
418 | depends on EDAC_ALTERA=y && MTD_NAND_DENALI | ||
419 | help | ||
420 | Support for error detection and correction on the | ||
421 | Altera NAND FIFO Memory for Altera SoCs. | ||
422 | |||
423 | config EDAC_ALTERA_DMA | ||
424 | bool "Altera DMA FIFO ECC" | ||
425 | depends on EDAC_ALTERA=y && PL330_DMA=y | ||
426 | help | ||
427 | Support for error detection and correction on the | ||
428 | Altera DMA FIFO Memory for Altera SoCs. | ||
429 | |||
430 | config EDAC_ALTERA_USB | ||
431 | bool "Altera USB FIFO ECC" | ||
432 | depends on EDAC_ALTERA=y && USB_DWC2 | ||
433 | help | ||
434 | Support for error detection and correction on the | ||
435 | Altera USB FIFO Memory for Altera SoCs. | ||
436 | |||
437 | config EDAC_ALTERA_QSPI | ||
438 | bool "Altera QSPI FIFO ECC" | ||
439 | depends on EDAC_ALTERA=y && SPI_CADENCE_QUADSPI | ||
440 | help | ||
441 | Support for error detection and correction on the | ||
442 | Altera QSPI FIFO Memory for Altera SoCs. | ||
443 | |||
444 | config EDAC_ALTERA_SDMMC | ||
445 | bool "Altera SDMMC FIFO ECC" | ||
446 | depends on EDAC_ALTERA=y && MMC_DW | ||
447 | help | ||
448 | Support for error detection and correction on the | ||
449 | Altera SDMMC FIFO Memory for Altera SoCs. | ||
450 | |||
409 | config EDAC_SYNOPSYS | 451 | config EDAC_SYNOPSYS |
410 | tristate "Synopsys DDR Memory Controller" | 452 | tristate "Synopsys DDR Memory Controller" |
411 | depends on EDAC_MM_EDAC && ARCH_ZYNQ | 453 | depends on EDAC_MM_EDAC && ARCH_ZYNQ |
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index 986049925b08..88e472e8b9a9 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile | |||
@@ -51,7 +51,13 @@ amd64_edac_mod-$(CONFIG_EDAC_AMD64_ERROR_INJECTION) += amd64_edac_inj.o | |||
51 | obj-$(CONFIG_EDAC_AMD64) += amd64_edac_mod.o | 51 | obj-$(CONFIG_EDAC_AMD64) += amd64_edac_mod.o |
52 | 52 | ||
53 | obj-$(CONFIG_EDAC_PASEMI) += pasemi_edac.o | 53 | obj-$(CONFIG_EDAC_PASEMI) += pasemi_edac.o |
54 | obj-$(CONFIG_EDAC_MPC85XX) += mpc85xx_edac.o | 54 | |
55 | mpc85xx_edac_mod-y := fsl_ddr_edac.o mpc85xx_edac.o | ||
56 | obj-$(CONFIG_EDAC_MPC85XX) += mpc85xx_edac_mod.o | ||
57 | |||
58 | layerscape_edac_mod-y := fsl_ddr_edac.o layerscape_edac.o | ||
59 | obj-$(CONFIG_EDAC_LAYERSCAPE) += layerscape_edac_mod.o | ||
60 | |||
55 | obj-$(CONFIG_EDAC_MV64X60) += mv64x60_edac.o | 61 | obj-$(CONFIG_EDAC_MV64X60) += mv64x60_edac.o |
56 | obj-$(CONFIG_EDAC_CELL) += cell_edac.o | 62 | obj-$(CONFIG_EDAC_CELL) += cell_edac.o |
57 | obj-$(CONFIG_EDAC_PPC4XX) += ppc4xx_edac.o | 63 | obj-$(CONFIG_EDAC_PPC4XX) += ppc4xx_edac.o |
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 2398d0701f5b..58d3e2b39b5b 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c | |||
@@ -203,7 +203,7 @@ static void altr_sdr_mc_create_debugfs_nodes(struct mem_ctl_info *mci) | |||
203 | if (!mci->debugfs) | 203 | if (!mci->debugfs) |
204 | return; | 204 | return; |
205 | 205 | ||
206 | edac_debugfs_create_file("inject_ctrl", S_IWUSR, mci->debugfs, mci, | 206 | edac_debugfs_create_file("altr_trigger", S_IWUSR, mci->debugfs, mci, |
207 | &altr_sdr_mc_debug_inject_fops); | 207 | &altr_sdr_mc_debug_inject_fops); |
208 | } | 208 | } |
209 | 209 | ||
@@ -680,7 +680,7 @@ static void altr_create_edacdev_dbgfs(struct edac_device_ctl_info *edac_dci, | |||
680 | if (!drvdata->debugfs_dir) | 680 | if (!drvdata->debugfs_dir) |
681 | return; | 681 | return; |
682 | 682 | ||
683 | if (!edac_debugfs_create_file(priv->dbgfs_name, S_IWUSR, | 683 | if (!edac_debugfs_create_file("altr_trigger", S_IWUSR, |
684 | drvdata->debugfs_dir, edac_dci, | 684 | drvdata->debugfs_dir, edac_dci, |
685 | priv->inject_fops)) | 685 | priv->inject_fops)) |
686 | debugfs_remove_recursive(drvdata->debugfs_dir); | 686 | debugfs_remove_recursive(drvdata->debugfs_dir); |
@@ -1108,7 +1108,6 @@ static const struct edac_device_prv_data ocramecc_data = { | |||
1108 | .setup = altr_check_ecc_deps, | 1108 | .setup = altr_check_ecc_deps, |
1109 | .ce_clear_mask = (ALTR_OCR_ECC_EN | ALTR_OCR_ECC_SERR), | 1109 | .ce_clear_mask = (ALTR_OCR_ECC_EN | ALTR_OCR_ECC_SERR), |
1110 | .ue_clear_mask = (ALTR_OCR_ECC_EN | ALTR_OCR_ECC_DERR), | 1110 | .ue_clear_mask = (ALTR_OCR_ECC_EN | ALTR_OCR_ECC_DERR), |
1111 | .dbgfs_name = "altr_ocram_trigger", | ||
1112 | .alloc_mem = ocram_alloc_mem, | 1111 | .alloc_mem = ocram_alloc_mem, |
1113 | .free_mem = ocram_free_mem, | 1112 | .free_mem = ocram_free_mem, |
1114 | .ecc_enable_mask = ALTR_OCR_ECC_EN, | 1113 | .ecc_enable_mask = ALTR_OCR_ECC_EN, |
@@ -1125,7 +1124,6 @@ static const struct edac_device_prv_data a10_ocramecc_data = { | |||
1125 | .ce_clear_mask = ALTR_A10_ECC_SERRPENA, | 1124 | .ce_clear_mask = ALTR_A10_ECC_SERRPENA, |
1126 | .ue_clear_mask = ALTR_A10_ECC_DERRPENA, | 1125 | .ue_clear_mask = ALTR_A10_ECC_DERRPENA, |
1127 | .irq_status_mask = A10_SYSMGR_ECC_INTSTAT_OCRAM, | 1126 | .irq_status_mask = A10_SYSMGR_ECC_INTSTAT_OCRAM, |
1128 | .dbgfs_name = "altr_ocram_trigger", | ||
1129 | .ecc_enable_mask = ALTR_A10_OCRAM_ECC_EN_CTL, | 1127 | .ecc_enable_mask = ALTR_A10_OCRAM_ECC_EN_CTL, |
1130 | .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, | 1128 | .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, |
1131 | .ce_set_mask = ALTR_A10_ECC_TSERRA, | 1129 | .ce_set_mask = ALTR_A10_ECC_TSERRA, |
@@ -1228,7 +1226,6 @@ static const struct edac_device_prv_data l2ecc_data = { | |||
1228 | .setup = altr_l2_check_deps, | 1226 | .setup = altr_l2_check_deps, |
1229 | .ce_clear_mask = 0, | 1227 | .ce_clear_mask = 0, |
1230 | .ue_clear_mask = 0, | 1228 | .ue_clear_mask = 0, |
1231 | .dbgfs_name = "altr_l2_trigger", | ||
1232 | .alloc_mem = l2_alloc_mem, | 1229 | .alloc_mem = l2_alloc_mem, |
1233 | .free_mem = l2_free_mem, | 1230 | .free_mem = l2_free_mem, |
1234 | .ecc_enable_mask = ALTR_L2_ECC_EN, | 1231 | .ecc_enable_mask = ALTR_L2_ECC_EN, |
@@ -1244,7 +1241,6 @@ static const struct edac_device_prv_data a10_l2ecc_data = { | |||
1244 | .ce_clear_mask = ALTR_A10_L2_ECC_SERR_CLR, | 1241 | .ce_clear_mask = ALTR_A10_L2_ECC_SERR_CLR, |
1245 | .ue_clear_mask = ALTR_A10_L2_ECC_MERR_CLR, | 1242 | .ue_clear_mask = ALTR_A10_L2_ECC_MERR_CLR, |
1246 | .irq_status_mask = A10_SYSMGR_ECC_INTSTAT_L2, | 1243 | .irq_status_mask = A10_SYSMGR_ECC_INTSTAT_L2, |
1247 | .dbgfs_name = "altr_l2_trigger", | ||
1248 | .alloc_mem = l2_alloc_mem, | 1244 | .alloc_mem = l2_alloc_mem, |
1249 | .free_mem = l2_free_mem, | 1245 | .free_mem = l2_free_mem, |
1250 | .ecc_enable_mask = ALTR_A10_L2_ECC_EN_CTL, | 1246 | .ecc_enable_mask = ALTR_A10_L2_ECC_EN_CTL, |
@@ -1266,7 +1262,6 @@ static const struct edac_device_prv_data a10_enetecc_data = { | |||
1266 | .setup = altr_check_ecc_deps, | 1262 | .setup = altr_check_ecc_deps, |
1267 | .ce_clear_mask = ALTR_A10_ECC_SERRPENA, | 1263 | .ce_clear_mask = ALTR_A10_ECC_SERRPENA, |
1268 | .ue_clear_mask = ALTR_A10_ECC_DERRPENA, | 1264 | .ue_clear_mask = ALTR_A10_ECC_DERRPENA, |
1269 | .dbgfs_name = "altr_trigger", | ||
1270 | .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL, | 1265 | .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL, |
1271 | .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, | 1266 | .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, |
1272 | .ce_set_mask = ALTR_A10_ECC_TSERRA, | 1267 | .ce_set_mask = ALTR_A10_ECC_TSERRA, |
@@ -1285,6 +1280,292 @@ early_initcall(socfpga_init_ethernet_ecc); | |||
1285 | 1280 | ||
1286 | #endif /* CONFIG_EDAC_ALTERA_ETHERNET */ | 1281 | #endif /* CONFIG_EDAC_ALTERA_ETHERNET */ |
1287 | 1282 | ||
1283 | /********************** NAND Device Functions **********************/ | ||
1284 | |||
1285 | #ifdef CONFIG_EDAC_ALTERA_NAND | ||
1286 | |||
1287 | static const struct edac_device_prv_data a10_nandecc_data = { | ||
1288 | .setup = altr_check_ecc_deps, | ||
1289 | .ce_clear_mask = ALTR_A10_ECC_SERRPENA, | ||
1290 | .ue_clear_mask = ALTR_A10_ECC_DERRPENA, | ||
1291 | .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL, | ||
1292 | .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, | ||
1293 | .ce_set_mask = ALTR_A10_ECC_TSERRA, | ||
1294 | .ue_set_mask = ALTR_A10_ECC_TDERRA, | ||
1295 | .set_err_ofst = ALTR_A10_ECC_INTTEST_OFST, | ||
1296 | .ecc_irq_handler = altr_edac_a10_ecc_irq, | ||
1297 | .inject_fops = &altr_edac_a10_device_inject_fops, | ||
1298 | }; | ||
1299 | |||
1300 | static int __init socfpga_init_nand_ecc(void) | ||
1301 | { | ||
1302 | return altr_init_a10_ecc_device_type("altr,socfpga-nand-ecc"); | ||
1303 | } | ||
1304 | |||
1305 | early_initcall(socfpga_init_nand_ecc); | ||
1306 | |||
1307 | #endif /* CONFIG_EDAC_ALTERA_NAND */ | ||
1308 | |||
1309 | /********************** DMA Device Functions **********************/ | ||
1310 | |||
1311 | #ifdef CONFIG_EDAC_ALTERA_DMA | ||
1312 | |||
1313 | static const struct edac_device_prv_data a10_dmaecc_data = { | ||
1314 | .setup = altr_check_ecc_deps, | ||
1315 | .ce_clear_mask = ALTR_A10_ECC_SERRPENA, | ||
1316 | .ue_clear_mask = ALTR_A10_ECC_DERRPENA, | ||
1317 | .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL, | ||
1318 | .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, | ||
1319 | .ce_set_mask = ALTR_A10_ECC_TSERRA, | ||
1320 | .ue_set_mask = ALTR_A10_ECC_TDERRA, | ||
1321 | .set_err_ofst = ALTR_A10_ECC_INTTEST_OFST, | ||
1322 | .ecc_irq_handler = altr_edac_a10_ecc_irq, | ||
1323 | .inject_fops = &altr_edac_a10_device_inject_fops, | ||
1324 | }; | ||
1325 | |||
1326 | static int __init socfpga_init_dma_ecc(void) | ||
1327 | { | ||
1328 | return altr_init_a10_ecc_device_type("altr,socfpga-dma-ecc"); | ||
1329 | } | ||
1330 | |||
1331 | early_initcall(socfpga_init_dma_ecc); | ||
1332 | |||
1333 | #endif /* CONFIG_EDAC_ALTERA_DMA */ | ||
1334 | |||
1335 | /********************** USB Device Functions **********************/ | ||
1336 | |||
1337 | #ifdef CONFIG_EDAC_ALTERA_USB | ||
1338 | |||
1339 | static const struct edac_device_prv_data a10_usbecc_data = { | ||
1340 | .setup = altr_check_ecc_deps, | ||
1341 | .ce_clear_mask = ALTR_A10_ECC_SERRPENA, | ||
1342 | .ue_clear_mask = ALTR_A10_ECC_DERRPENA, | ||
1343 | .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL, | ||
1344 | .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, | ||
1345 | .ce_set_mask = ALTR_A10_ECC_TSERRA, | ||
1346 | .ue_set_mask = ALTR_A10_ECC_TDERRA, | ||
1347 | .set_err_ofst = ALTR_A10_ECC_INTTEST_OFST, | ||
1348 | .ecc_irq_handler = altr_edac_a10_ecc_irq, | ||
1349 | .inject_fops = &altr_edac_a10_device_inject_fops, | ||
1350 | }; | ||
1351 | |||
1352 | static int __init socfpga_init_usb_ecc(void) | ||
1353 | { | ||
1354 | return altr_init_a10_ecc_device_type("altr,socfpga-usb-ecc"); | ||
1355 | } | ||
1356 | |||
1357 | early_initcall(socfpga_init_usb_ecc); | ||
1358 | |||
1359 | #endif /* CONFIG_EDAC_ALTERA_USB */ | ||
1360 | |||
1361 | /********************** QSPI Device Functions **********************/ | ||
1362 | |||
1363 | #ifdef CONFIG_EDAC_ALTERA_QSPI | ||
1364 | |||
1365 | static const struct edac_device_prv_data a10_qspiecc_data = { | ||
1366 | .setup = altr_check_ecc_deps, | ||
1367 | .ce_clear_mask = ALTR_A10_ECC_SERRPENA, | ||
1368 | .ue_clear_mask = ALTR_A10_ECC_DERRPENA, | ||
1369 | .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL, | ||
1370 | .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, | ||
1371 | .ce_set_mask = ALTR_A10_ECC_TSERRA, | ||
1372 | .ue_set_mask = ALTR_A10_ECC_TDERRA, | ||
1373 | .set_err_ofst = ALTR_A10_ECC_INTTEST_OFST, | ||
1374 | .ecc_irq_handler = altr_edac_a10_ecc_irq, | ||
1375 | .inject_fops = &altr_edac_a10_device_inject_fops, | ||
1376 | }; | ||
1377 | |||
1378 | static int __init socfpga_init_qspi_ecc(void) | ||
1379 | { | ||
1380 | return altr_init_a10_ecc_device_type("altr,socfpga-qspi-ecc"); | ||
1381 | } | ||
1382 | |||
1383 | early_initcall(socfpga_init_qspi_ecc); | ||
1384 | |||
1385 | #endif /* CONFIG_EDAC_ALTERA_QSPI */ | ||
1386 | |||
1387 | /********************* SDMMC Device Functions **********************/ | ||
1388 | |||
1389 | #ifdef CONFIG_EDAC_ALTERA_SDMMC | ||
1390 | |||
1391 | static const struct edac_device_prv_data a10_sdmmceccb_data; | ||
1392 | static int altr_portb_setup(struct altr_edac_device_dev *device) | ||
1393 | { | ||
1394 | struct edac_device_ctl_info *dci; | ||
1395 | struct altr_edac_device_dev *altdev; | ||
1396 | char *ecc_name = "sdmmcb-ecc"; | ||
1397 | int edac_idx, rc; | ||
1398 | struct device_node *np; | ||
1399 | const struct edac_device_prv_data *prv = &a10_sdmmceccb_data; | ||
1400 | |||
1401 | rc = altr_check_ecc_deps(device); | ||
1402 | if (rc) | ||
1403 | return rc; | ||
1404 | |||
1405 | np = of_find_compatible_node(NULL, NULL, "altr,socfpga-sdmmc-ecc"); | ||
1406 | if (!np) { | ||
1407 | edac_printk(KERN_WARNING, EDAC_DEVICE, "SDMMC node not found\n"); | ||
1408 | return -ENODEV; | ||
1409 | } | ||
1410 | |||
1411 | /* Create the PortB EDAC device */ | ||
1412 | edac_idx = edac_device_alloc_index(); | ||
1413 | dci = edac_device_alloc_ctl_info(sizeof(*altdev), ecc_name, 1, | ||
1414 | ecc_name, 1, 0, NULL, 0, edac_idx); | ||
1415 | if (!dci) { | ||
1416 | edac_printk(KERN_ERR, EDAC_DEVICE, | ||
1417 | "%s: Unable to allocate PortB EDAC device\n", | ||
1418 | ecc_name); | ||
1419 | return -ENOMEM; | ||
1420 | } | ||
1421 | |||
1422 | /* Initialize the PortB EDAC device structure from PortA structure */ | ||
1423 | altdev = dci->pvt_info; | ||
1424 | *altdev = *device; | ||
1425 | |||
1426 | if (!devres_open_group(&altdev->ddev, altr_portb_setup, GFP_KERNEL)) | ||
1427 | return -ENOMEM; | ||
1428 | |||
1429 | /* Update PortB specific values */ | ||
1430 | altdev->edac_dev_name = ecc_name; | ||
1431 | altdev->edac_idx = edac_idx; | ||
1432 | altdev->edac_dev = dci; | ||
1433 | altdev->data = prv; | ||
1434 | dci->dev = &altdev->ddev; | ||
1435 | dci->ctl_name = "Altera ECC Manager"; | ||
1436 | dci->mod_name = ecc_name; | ||
1437 | dci->dev_name = ecc_name; | ||
1438 | |||
1439 | /* Update the IRQs for PortB */ | ||
1440 | altdev->sb_irq = irq_of_parse_and_map(np, 2); | ||
1441 | if (!altdev->sb_irq) { | ||
1442 | edac_printk(KERN_ERR, EDAC_DEVICE, "Error PortB SBIRQ alloc\n"); | ||
1443 | rc = -ENODEV; | ||
1444 | goto err_release_group_1; | ||
1445 | } | ||
1446 | rc = devm_request_irq(&altdev->ddev, altdev->sb_irq, | ||
1447 | prv->ecc_irq_handler, | ||
1448 | IRQF_ONESHOT | IRQF_TRIGGER_HIGH, | ||
1449 | ecc_name, altdev); | ||
1450 | if (rc) { | ||
1451 | edac_printk(KERN_ERR, EDAC_DEVICE, "PortB SBERR IRQ error\n"); | ||
1452 | goto err_release_group_1; | ||
1453 | } | ||
1454 | |||
1455 | altdev->db_irq = irq_of_parse_and_map(np, 3); | ||
1456 | if (!altdev->db_irq) { | ||
1457 | edac_printk(KERN_ERR, EDAC_DEVICE, "Error PortB DBIRQ alloc\n"); | ||
1458 | rc = -ENODEV; | ||
1459 | goto err_release_group_1; | ||
1460 | } | ||
1461 | rc = devm_request_irq(&altdev->ddev, altdev->db_irq, | ||
1462 | prv->ecc_irq_handler, | ||
1463 | IRQF_ONESHOT | IRQF_TRIGGER_HIGH, | ||
1464 | ecc_name, altdev); | ||
1465 | if (rc) { | ||
1466 | edac_printk(KERN_ERR, EDAC_DEVICE, "PortB DBERR IRQ error\n"); | ||
1467 | goto err_release_group_1; | ||
1468 | } | ||
1469 | |||
1470 | rc = edac_device_add_device(dci); | ||
1471 | if (rc) { | ||
1472 | edac_printk(KERN_ERR, EDAC_DEVICE, | ||
1473 | "edac_device_add_device portB failed\n"); | ||
1474 | rc = -ENOMEM; | ||
1475 | goto err_release_group_1; | ||
1476 | } | ||
1477 | altr_create_edacdev_dbgfs(dci, prv); | ||
1478 | |||
1479 | list_add(&altdev->next, &altdev->edac->a10_ecc_devices); | ||
1480 | |||
1481 | devres_remove_group(&altdev->ddev, altr_portb_setup); | ||
1482 | |||
1483 | return 0; | ||
1484 | |||
1485 | err_release_group_1: | ||
1486 | edac_device_free_ctl_info(dci); | ||
1487 | devres_release_group(&altdev->ddev, altr_portb_setup); | ||
1488 | edac_printk(KERN_ERR, EDAC_DEVICE, | ||
1489 | "%s:Error setting up EDAC device: %d\n", ecc_name, rc); | ||
1490 | return rc; | ||
1491 | } | ||
1492 | |||
1493 | static irqreturn_t altr_edac_a10_ecc_irq_portb(int irq, void *dev_id) | ||
1494 | { | ||
1495 | struct altr_edac_device_dev *ad = dev_id; | ||
1496 | void __iomem *base = ad->base; | ||
1497 | const struct edac_device_prv_data *priv = ad->data; | ||
1498 | |||
1499 | if (irq == ad->sb_irq) { | ||
1500 | writel(priv->ce_clear_mask, | ||
1501 | base + ALTR_A10_ECC_INTSTAT_OFST); | ||
1502 | edac_device_handle_ce(ad->edac_dev, 0, 0, ad->edac_dev_name); | ||
1503 | return IRQ_HANDLED; | ||
1504 | } else if (irq == ad->db_irq) { | ||
1505 | writel(priv->ue_clear_mask, | ||
1506 | base + ALTR_A10_ECC_INTSTAT_OFST); | ||
1507 | edac_device_handle_ue(ad->edac_dev, 0, 0, ad->edac_dev_name); | ||
1508 | return IRQ_HANDLED; | ||
1509 | } | ||
1510 | |||
1511 | WARN_ONCE(1, "Unhandled IRQ%d on Port B.", irq); | ||
1512 | |||
1513 | return IRQ_NONE; | ||
1514 | } | ||
1515 | |||
1516 | static const struct edac_device_prv_data a10_sdmmcecca_data = { | ||
1517 | .setup = altr_portb_setup, | ||
1518 | .ce_clear_mask = ALTR_A10_ECC_SERRPENA, | ||
1519 | .ue_clear_mask = ALTR_A10_ECC_DERRPENA, | ||
1520 | .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL, | ||
1521 | .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, | ||
1522 | .ce_set_mask = ALTR_A10_ECC_SERRPENA, | ||
1523 | .ue_set_mask = ALTR_A10_ECC_DERRPENA, | ||
1524 | .set_err_ofst = ALTR_A10_ECC_INTTEST_OFST, | ||
1525 | .ecc_irq_handler = altr_edac_a10_ecc_irq, | ||
1526 | .inject_fops = &altr_edac_a10_device_inject_fops, | ||
1527 | }; | ||
1528 | |||
1529 | static const struct edac_device_prv_data a10_sdmmceccb_data = { | ||
1530 | .setup = altr_portb_setup, | ||
1531 | .ce_clear_mask = ALTR_A10_ECC_SERRPENB, | ||
1532 | .ue_clear_mask = ALTR_A10_ECC_DERRPENB, | ||
1533 | .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL, | ||
1534 | .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, | ||
1535 | .ce_set_mask = ALTR_A10_ECC_TSERRB, | ||
1536 | .ue_set_mask = ALTR_A10_ECC_TDERRB, | ||
1537 | .set_err_ofst = ALTR_A10_ECC_INTTEST_OFST, | ||
1538 | .ecc_irq_handler = altr_edac_a10_ecc_irq_portb, | ||
1539 | .inject_fops = &altr_edac_a10_device_inject_fops, | ||
1540 | }; | ||
1541 | |||
1542 | static int __init socfpga_init_sdmmc_ecc(void) | ||
1543 | { | ||
1544 | int rc = -ENODEV; | ||
1545 | struct device_node *child = of_find_compatible_node(NULL, NULL, | ||
1546 | "altr,socfpga-sdmmc-ecc"); | ||
1547 | if (!child) { | ||
1548 | edac_printk(KERN_WARNING, EDAC_DEVICE, "SDMMC node not found\n"); | ||
1549 | return -ENODEV; | ||
1550 | } | ||
1551 | |||
1552 | if (!of_device_is_available(child)) | ||
1553 | goto exit; | ||
1554 | |||
1555 | if (validate_parent_available(child)) | ||
1556 | goto exit; | ||
1557 | |||
1558 | rc = altr_init_a10_ecc_block(child, ALTR_A10_SDMMC_IRQ_MASK, | ||
1559 | a10_sdmmcecca_data.ecc_enable_mask, 1); | ||
1560 | exit: | ||
1561 | of_node_put(child); | ||
1562 | return rc; | ||
1563 | } | ||
1564 | |||
1565 | early_initcall(socfpga_init_sdmmc_ecc); | ||
1566 | |||
1567 | #endif /* CONFIG_EDAC_ALTERA_SDMMC */ | ||
1568 | |||
1288 | /********************* Arria10 EDAC Device Functions *************************/ | 1569 | /********************* Arria10 EDAC Device Functions *************************/ |
1289 | static const struct of_device_id altr_edac_a10_device_of_match[] = { | 1570 | static const struct of_device_id altr_edac_a10_device_of_match[] = { |
1290 | #ifdef CONFIG_EDAC_ALTERA_L2C | 1571 | #ifdef CONFIG_EDAC_ALTERA_L2C |
@@ -1298,6 +1579,21 @@ static const struct of_device_id altr_edac_a10_device_of_match[] = { | |||
1298 | { .compatible = "altr,socfpga-eth-mac-ecc", | 1579 | { .compatible = "altr,socfpga-eth-mac-ecc", |
1299 | .data = &a10_enetecc_data }, | 1580 | .data = &a10_enetecc_data }, |
1300 | #endif | 1581 | #endif |
1582 | #ifdef CONFIG_EDAC_ALTERA_NAND | ||
1583 | { .compatible = "altr,socfpga-nand-ecc", .data = &a10_nandecc_data }, | ||
1584 | #endif | ||
1585 | #ifdef CONFIG_EDAC_ALTERA_DMA | ||
1586 | { .compatible = "altr,socfpga-dma-ecc", .data = &a10_dmaecc_data }, | ||
1587 | #endif | ||
1588 | #ifdef CONFIG_EDAC_ALTERA_USB | ||
1589 | { .compatible = "altr,socfpga-usb-ecc", .data = &a10_usbecc_data }, | ||
1590 | #endif | ||
1591 | #ifdef CONFIG_EDAC_ALTERA_QSPI | ||
1592 | { .compatible = "altr,socfpga-qspi-ecc", .data = &a10_qspiecc_data }, | ||
1593 | #endif | ||
1594 | #ifdef CONFIG_EDAC_ALTERA_SDMMC | ||
1595 | { .compatible = "altr,socfpga-sdmmc-ecc", .data = &a10_sdmmcecca_data }, | ||
1596 | #endif | ||
1301 | {}, | 1597 | {}, |
1302 | }; | 1598 | }; |
1303 | MODULE_DEVICE_TABLE(of, altr_edac_a10_device_of_match); | 1599 | MODULE_DEVICE_TABLE(of, altr_edac_a10_device_of_match); |
@@ -1451,11 +1747,11 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, | |||
1451 | rc = -ENODEV; | 1747 | rc = -ENODEV; |
1452 | goto err_release_group1; | 1748 | goto err_release_group1; |
1453 | } | 1749 | } |
1454 | rc = devm_request_irq(edac->dev, altdev->sb_irq, | 1750 | rc = devm_request_irq(edac->dev, altdev->sb_irq, prv->ecc_irq_handler, |
1455 | prv->ecc_irq_handler, | 1751 | IRQF_ONESHOT | IRQF_TRIGGER_HIGH, |
1456 | IRQF_SHARED, ecc_name, altdev); | 1752 | ecc_name, altdev); |
1457 | if (rc) { | 1753 | if (rc) { |
1458 | edac_printk(KERN_ERR, EDAC_DEVICE, "No DBERR IRQ resource\n"); | 1754 | edac_printk(KERN_ERR, EDAC_DEVICE, "No SBERR IRQ resource\n"); |
1459 | goto err_release_group1; | 1755 | goto err_release_group1; |
1460 | } | 1756 | } |
1461 | 1757 | ||
@@ -1465,9 +1761,9 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, | |||
1465 | rc = -ENODEV; | 1761 | rc = -ENODEV; |
1466 | goto err_release_group1; | 1762 | goto err_release_group1; |
1467 | } | 1763 | } |
1468 | rc = devm_request_irq(edac->dev, altdev->db_irq, | 1764 | rc = devm_request_irq(edac->dev, altdev->db_irq, prv->ecc_irq_handler, |
1469 | prv->ecc_irq_handler, | 1765 | IRQF_ONESHOT | IRQF_TRIGGER_HIGH, |
1470 | IRQF_SHARED, ecc_name, altdev); | 1766 | ecc_name, altdev); |
1471 | if (rc) { | 1767 | if (rc) { |
1472 | edac_printk(KERN_ERR, EDAC_DEVICE, "No DBERR IRQ resource\n"); | 1768 | edac_printk(KERN_ERR, EDAC_DEVICE, "No DBERR IRQ resource\n"); |
1473 | goto err_release_group1; | 1769 | goto err_release_group1; |
@@ -1526,7 +1822,7 @@ static int a10_eccmgr_irqdomain_map(struct irq_domain *d, unsigned int irq, | |||
1526 | return 0; | 1822 | return 0; |
1527 | } | 1823 | } |
1528 | 1824 | ||
1529 | struct irq_domain_ops a10_eccmgr_ic_ops = { | 1825 | static struct irq_domain_ops a10_eccmgr_ic_ops = { |
1530 | .map = a10_eccmgr_irqdomain_map, | 1826 | .map = a10_eccmgr_irqdomain_map, |
1531 | .xlate = irq_domain_xlate_twocell, | 1827 | .xlate = irq_domain_xlate_twocell, |
1532 | }; | 1828 | }; |
@@ -1584,15 +1880,19 @@ static int altr_edac_a10_probe(struct platform_device *pdev) | |||
1584 | for_each_child_of_node(pdev->dev.of_node, child) { | 1880 | for_each_child_of_node(pdev->dev.of_node, child) { |
1585 | if (!of_device_is_available(child)) | 1881 | if (!of_device_is_available(child)) |
1586 | continue; | 1882 | continue; |
1587 | if (of_device_is_compatible(child, "altr,socfpga-a10-l2-ecc")) | 1883 | |
1588 | altr_edac_a10_device_add(edac, child); | 1884 | if (of_device_is_compatible(child, "altr,socfpga-a10-l2-ecc") || |
1589 | else if ((of_device_is_compatible(child, | 1885 | of_device_is_compatible(child, "altr,socfpga-a10-ocram-ecc") || |
1590 | "altr,socfpga-a10-ocram-ecc")) || | 1886 | of_device_is_compatible(child, "altr,socfpga-eth-mac-ecc") || |
1591 | (of_device_is_compatible(child, | 1887 | of_device_is_compatible(child, "altr,socfpga-nand-ecc") || |
1592 | "altr,socfpga-eth-mac-ecc"))) | 1888 | of_device_is_compatible(child, "altr,socfpga-dma-ecc") || |
1889 | of_device_is_compatible(child, "altr,socfpga-usb-ecc") || | ||
1890 | of_device_is_compatible(child, "altr,socfpga-qspi-ecc") || | ||
1891 | of_device_is_compatible(child, "altr,socfpga-sdmmc-ecc")) | ||
1892 | |||
1593 | altr_edac_a10_device_add(edac, child); | 1893 | altr_edac_a10_device_add(edac, child); |
1594 | else if (of_device_is_compatible(child, | 1894 | |
1595 | "altr,sdram-edac-a10")) | 1895 | else if (of_device_is_compatible(child, "altr,sdram-edac-a10")) |
1596 | of_platform_populate(pdev->dev.of_node, | 1896 | of_platform_populate(pdev->dev.of_node, |
1597 | altr_sdram_ctrl_of_match, | 1897 | altr_sdram_ctrl_of_match, |
1598 | NULL, &pdev->dev); | 1898 | NULL, &pdev->dev); |
diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h index 687d8e754d36..cbc96290f743 100644 --- a/drivers/edac/altera_edac.h +++ b/drivers/edac/altera_edac.h | |||
@@ -250,6 +250,8 @@ struct altr_sdram_mc_data { | |||
250 | #define ALTR_A10_ECC_INTTEST_OFST 0x24 | 250 | #define ALTR_A10_ECC_INTTEST_OFST 0x24 |
251 | #define ALTR_A10_ECC_TSERRA BIT(0) | 251 | #define ALTR_A10_ECC_TSERRA BIT(0) |
252 | #define ALTR_A10_ECC_TDERRA BIT(8) | 252 | #define ALTR_A10_ECC_TDERRA BIT(8) |
253 | #define ALTR_A10_ECC_TSERRB BIT(16) | ||
254 | #define ALTR_A10_ECC_TDERRB BIT(24) | ||
253 | 255 | ||
254 | /* ECC Manager Defines */ | 256 | /* ECC Manager Defines */ |
255 | #define A10_SYSMGR_ECC_INTMASK_SET_OFST 0x94 | 257 | #define A10_SYSMGR_ECC_INTMASK_SET_OFST 0x94 |
@@ -288,6 +290,9 @@ struct altr_sdram_mc_data { | |||
288 | /* Arria 10 Ethernet ECC Management Group Defines */ | 290 | /* Arria 10 Ethernet ECC Management Group Defines */ |
289 | #define ALTR_A10_COMMON_ECC_EN_CTL BIT(0) | 291 | #define ALTR_A10_COMMON_ECC_EN_CTL BIT(0) |
290 | 292 | ||
293 | /* Arria 10 SDMMC ECC Management Group Defines */ | ||
294 | #define ALTR_A10_SDMMC_IRQ_MASK (BIT(16) | BIT(15)) | ||
295 | |||
291 | /* A10 ECC Controller memory initialization timeout */ | 296 | /* A10 ECC Controller memory initialization timeout */ |
292 | #define ALTR_A10_ECC_INIT_WATCHDOG_10US 10000 | 297 | #define ALTR_A10_ECC_INIT_WATCHDOG_10US 10000 |
293 | 298 | ||
@@ -298,7 +303,6 @@ struct edac_device_prv_data { | |||
298 | int ce_clear_mask; | 303 | int ce_clear_mask; |
299 | int ue_clear_mask; | 304 | int ue_clear_mask; |
300 | int irq_status_mask; | 305 | int irq_status_mask; |
301 | char dbgfs_name[20]; | ||
302 | void * (*alloc_mem)(size_t size, void **other); | 306 | void * (*alloc_mem)(size_t size, void **other); |
303 | void (*free_mem)(void *p, size_t size, void *other); | 307 | void (*free_mem)(void *p, size_t size, void *other); |
304 | int ecc_enable_mask; | 308 | int ecc_enable_mask; |
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 8c0ec2128907..ee181c53626f 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c | |||
@@ -1425,11 +1425,17 @@ static u8 f1x_determine_channel(struct amd64_pvt *pvt, u64 sys_addr, | |||
1425 | 1425 | ||
1426 | if (intlv_addr & 0x2) { | 1426 | if (intlv_addr & 0x2) { |
1427 | u8 shift = intlv_addr & 0x1 ? 9 : 6; | 1427 | u8 shift = intlv_addr & 0x1 ? 9 : 6; |
1428 | u32 temp = hweight_long((u32) ((sys_addr >> 16) & 0x1F)) % 2; | 1428 | u32 temp = hweight_long((u32) ((sys_addr >> 16) & 0x1F)) & 1; |
1429 | 1429 | ||
1430 | return ((sys_addr >> shift) & 1) ^ temp; | 1430 | return ((sys_addr >> shift) & 1) ^ temp; |
1431 | } | 1431 | } |
1432 | 1432 | ||
1433 | if (intlv_addr & 0x4) { | ||
1434 | u8 shift = intlv_addr & 0x1 ? 9 : 8; | ||
1435 | |||
1436 | return (sys_addr >> shift) & 1; | ||
1437 | } | ||
1438 | |||
1433 | return (sys_addr >> (12 + hweight8(intlv_en))) & 1; | 1439 | return (sys_addr >> (12 + hweight8(intlv_en))) & 1; |
1434 | } | 1440 | } |
1435 | 1441 | ||
@@ -1726,8 +1732,11 @@ static int f15_m30h_match_to_this_node(struct amd64_pvt *pvt, unsigned range, | |||
1726 | if (!(num_dcts_intlv % 2 == 0) || (num_dcts_intlv > 4)) | 1732 | if (!(num_dcts_intlv % 2 == 0) || (num_dcts_intlv > 4)) |
1727 | return -EINVAL; | 1733 | return -EINVAL; |
1728 | 1734 | ||
1729 | channel = f15_m30h_determine_channel(pvt, sys_addr, intlv_en, | 1735 | if (pvt->model >= 0x60) |
1730 | num_dcts_intlv, dct_sel); | 1736 | channel = f1x_determine_channel(pvt, sys_addr, false, intlv_en); |
1737 | else | ||
1738 | channel = f15_m30h_determine_channel(pvt, sys_addr, intlv_en, | ||
1739 | num_dcts_intlv, dct_sel); | ||
1731 | 1740 | ||
1732 | /* Verify we stay within the MAX number of channels allowed */ | 1741 | /* Verify we stay within the MAX number of channels allowed */ |
1733 | if (channel > 3) | 1742 | if (channel > 3) |
@@ -2961,6 +2970,15 @@ static void setup_pci_device(void) | |||
2961 | } | 2970 | } |
2962 | } | 2971 | } |
2963 | 2972 | ||
2973 | static const struct x86_cpu_id amd64_cpuids[] = { | ||
2974 | { X86_VENDOR_AMD, 0xF, X86_MODEL_ANY, X86_FEATURE_ANY, 0 }, | ||
2975 | { X86_VENDOR_AMD, 0x10, X86_MODEL_ANY, X86_FEATURE_ANY, 0 }, | ||
2976 | { X86_VENDOR_AMD, 0x15, X86_MODEL_ANY, X86_FEATURE_ANY, 0 }, | ||
2977 | { X86_VENDOR_AMD, 0x16, X86_MODEL_ANY, X86_FEATURE_ANY, 0 }, | ||
2978 | { } | ||
2979 | }; | ||
2980 | MODULE_DEVICE_TABLE(x86cpu, amd64_cpuids); | ||
2981 | |||
2964 | static int __init amd64_edac_init(void) | 2982 | static int __init amd64_edac_init(void) |
2965 | { | 2983 | { |
2966 | int err = -ENODEV; | 2984 | int err = -ENODEV; |
diff --git a/drivers/edac/fsl_ddr_edac.c b/drivers/edac/fsl_ddr_edac.c new file mode 100644 index 000000000000..9774f52f0c3e --- /dev/null +++ b/drivers/edac/fsl_ddr_edac.c | |||
@@ -0,0 +1,633 @@ | |||
1 | /* | ||
2 | * Freescale Memory Controller kernel module | ||
3 | * | ||
4 | * Support Power-based SoCs including MPC85xx, MPC86xx, MPC83xx and | ||
5 | * ARM-based Layerscape SoCs including LS2xxx. Originally split | ||
6 | * out from mpc85xx_edac EDAC driver. | ||
7 | * | ||
8 | * Parts Copyrighted (c) 2013 by Freescale Semiconductor, Inc. | ||
9 | * | ||
10 | * Author: Dave Jiang <djiang@mvista.com> | ||
11 | * | ||
12 | * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under | ||
13 | * the terms of the GNU General Public License version 2. This program | ||
14 | * is licensed "as is" without any warranty of any kind, whether express | ||
15 | * or implied. | ||
16 | */ | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/ctype.h> | ||
21 | #include <linux/io.h> | ||
22 | #include <linux/mod_devicetable.h> | ||
23 | #include <linux/edac.h> | ||
24 | #include <linux/smp.h> | ||
25 | #include <linux/gfp.h> | ||
26 | |||
27 | #include <linux/of_platform.h> | ||
28 | #include <linux/of_device.h> | ||
29 | #include <linux/of_address.h> | ||
30 | #include "edac_module.h" | ||
31 | #include "edac_core.h" | ||
32 | #include "fsl_ddr_edac.h" | ||
33 | |||
34 | #define EDAC_MOD_STR "fsl_ddr_edac" | ||
35 | |||
36 | static int edac_mc_idx; | ||
37 | |||
38 | static u32 orig_ddr_err_disable; | ||
39 | static u32 orig_ddr_err_sbe; | ||
40 | static bool little_endian; | ||
41 | |||
42 | static inline u32 ddr_in32(void __iomem *addr) | ||
43 | { | ||
44 | return little_endian ? ioread32(addr) : ioread32be(addr); | ||
45 | } | ||
46 | |||
47 | static inline void ddr_out32(void __iomem *addr, u32 value) | ||
48 | { | ||
49 | if (little_endian) | ||
50 | iowrite32(value, addr); | ||
51 | else | ||
52 | iowrite32be(value, addr); | ||
53 | } | ||
54 | |||
55 | /************************ MC SYSFS parts ***********************************/ | ||
56 | |||
57 | #define to_mci(k) container_of(k, struct mem_ctl_info, dev) | ||
58 | |||
59 | static ssize_t fsl_mc_inject_data_hi_show(struct device *dev, | ||
60 | struct device_attribute *mattr, | ||
61 | char *data) | ||
62 | { | ||
63 | struct mem_ctl_info *mci = to_mci(dev); | ||
64 | struct fsl_mc_pdata *pdata = mci->pvt_info; | ||
65 | return sprintf(data, "0x%08x", | ||
66 | ddr_in32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_HI)); | ||
67 | } | ||
68 | |||
69 | static ssize_t fsl_mc_inject_data_lo_show(struct device *dev, | ||
70 | struct device_attribute *mattr, | ||
71 | char *data) | ||
72 | { | ||
73 | struct mem_ctl_info *mci = to_mci(dev); | ||
74 | struct fsl_mc_pdata *pdata = mci->pvt_info; | ||
75 | return sprintf(data, "0x%08x", | ||
76 | ddr_in32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_LO)); | ||
77 | } | ||
78 | |||
79 | static ssize_t fsl_mc_inject_ctrl_show(struct device *dev, | ||
80 | struct device_attribute *mattr, | ||
81 | char *data) | ||
82 | { | ||
83 | struct mem_ctl_info *mci = to_mci(dev); | ||
84 | struct fsl_mc_pdata *pdata = mci->pvt_info; | ||
85 | return sprintf(data, "0x%08x", | ||
86 | ddr_in32(pdata->mc_vbase + FSL_MC_ECC_ERR_INJECT)); | ||
87 | } | ||
88 | |||
89 | static ssize_t fsl_mc_inject_data_hi_store(struct device *dev, | ||
90 | struct device_attribute *mattr, | ||
91 | const char *data, size_t count) | ||
92 | { | ||
93 | struct mem_ctl_info *mci = to_mci(dev); | ||
94 | struct fsl_mc_pdata *pdata = mci->pvt_info; | ||
95 | unsigned long val; | ||
96 | int rc; | ||
97 | |||
98 | if (isdigit(*data)) { | ||
99 | rc = kstrtoul(data, 0, &val); | ||
100 | if (rc) | ||
101 | return rc; | ||
102 | |||
103 | ddr_out32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_HI, val); | ||
104 | return count; | ||
105 | } | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static ssize_t fsl_mc_inject_data_lo_store(struct device *dev, | ||
110 | struct device_attribute *mattr, | ||
111 | const char *data, size_t count) | ||
112 | { | ||
113 | struct mem_ctl_info *mci = to_mci(dev); | ||
114 | struct fsl_mc_pdata *pdata = mci->pvt_info; | ||
115 | unsigned long val; | ||
116 | int rc; | ||
117 | |||
118 | if (isdigit(*data)) { | ||
119 | rc = kstrtoul(data, 0, &val); | ||
120 | if (rc) | ||
121 | return rc; | ||
122 | |||
123 | ddr_out32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_LO, val); | ||
124 | return count; | ||
125 | } | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static ssize_t fsl_mc_inject_ctrl_store(struct device *dev, | ||
130 | struct device_attribute *mattr, | ||
131 | const char *data, size_t count) | ||
132 | { | ||
133 | struct mem_ctl_info *mci = to_mci(dev); | ||
134 | struct fsl_mc_pdata *pdata = mci->pvt_info; | ||
135 | unsigned long val; | ||
136 | int rc; | ||
137 | |||
138 | if (isdigit(*data)) { | ||
139 | rc = kstrtoul(data, 0, &val); | ||
140 | if (rc) | ||
141 | return rc; | ||
142 | |||
143 | ddr_out32(pdata->mc_vbase + FSL_MC_ECC_ERR_INJECT, val); | ||
144 | return count; | ||
145 | } | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | DEVICE_ATTR(inject_data_hi, S_IRUGO | S_IWUSR, | ||
150 | fsl_mc_inject_data_hi_show, fsl_mc_inject_data_hi_store); | ||
151 | DEVICE_ATTR(inject_data_lo, S_IRUGO | S_IWUSR, | ||
152 | fsl_mc_inject_data_lo_show, fsl_mc_inject_data_lo_store); | ||
153 | DEVICE_ATTR(inject_ctrl, S_IRUGO | S_IWUSR, | ||
154 | fsl_mc_inject_ctrl_show, fsl_mc_inject_ctrl_store); | ||
155 | |||
156 | static struct attribute *fsl_ddr_dev_attrs[] = { | ||
157 | &dev_attr_inject_data_hi.attr, | ||
158 | &dev_attr_inject_data_lo.attr, | ||
159 | &dev_attr_inject_ctrl.attr, | ||
160 | NULL | ||
161 | }; | ||
162 | |||
163 | ATTRIBUTE_GROUPS(fsl_ddr_dev); | ||
164 | |||
165 | /**************************** MC Err device ***************************/ | ||
166 | |||
167 | /* | ||
168 | * Taken from table 8-55 in the MPC8641 User's Manual and/or 9-61 in the | ||
169 | * MPC8572 User's Manual. Each line represents a syndrome bit column as a | ||
170 | * 64-bit value, but split into an upper and lower 32-bit chunk. The labels | ||
171 | * below correspond to Freescale's manuals. | ||
172 | */ | ||
173 | static unsigned int ecc_table[16] = { | ||
174 | /* MSB LSB */ | ||
175 | /* [0:31] [32:63] */ | ||
176 | 0xf00fe11e, 0xc33c0ff7, /* Syndrome bit 7 */ | ||
177 | 0x00ff00ff, 0x00fff0ff, | ||
178 | 0x0f0f0f0f, 0x0f0fff00, | ||
179 | 0x11113333, 0x7777000f, | ||
180 | 0x22224444, 0x8888222f, | ||
181 | 0x44448888, 0xffff4441, | ||
182 | 0x8888ffff, 0x11118882, | ||
183 | 0xffff1111, 0x22221114, /* Syndrome bit 0 */ | ||
184 | }; | ||
185 | |||
186 | /* | ||
187 | * Calculate the correct ECC value for a 64-bit value specified by high:low | ||
188 | */ | ||
189 | static u8 calculate_ecc(u32 high, u32 low) | ||
190 | { | ||
191 | u32 mask_low; | ||
192 | u32 mask_high; | ||
193 | int bit_cnt; | ||
194 | u8 ecc = 0; | ||
195 | int i; | ||
196 | int j; | ||
197 | |||
198 | for (i = 0; i < 8; i++) { | ||
199 | mask_high = ecc_table[i * 2]; | ||
200 | mask_low = ecc_table[i * 2 + 1]; | ||
201 | bit_cnt = 0; | ||
202 | |||
203 | for (j = 0; j < 32; j++) { | ||
204 | if ((mask_high >> j) & 1) | ||
205 | bit_cnt ^= (high >> j) & 1; | ||
206 | if ((mask_low >> j) & 1) | ||
207 | bit_cnt ^= (low >> j) & 1; | ||
208 | } | ||
209 | |||
210 | ecc |= bit_cnt << i; | ||
211 | } | ||
212 | |||
213 | return ecc; | ||
214 | } | ||
215 | |||
216 | /* | ||
217 | * Create the syndrome code which is generated if the data line specified by | ||
218 | * 'bit' failed. Eg generate an 8-bit codes seen in Table 8-55 in the MPC8641 | ||
219 | * User's Manual and 9-61 in the MPC8572 User's Manual. | ||
220 | */ | ||
221 | static u8 syndrome_from_bit(unsigned int bit) { | ||
222 | int i; | ||
223 | u8 syndrome = 0; | ||
224 | |||
225 | /* | ||
226 | * Cycle through the upper or lower 32-bit portion of each value in | ||
227 | * ecc_table depending on if 'bit' is in the upper or lower half of | ||
228 | * 64-bit data. | ||
229 | */ | ||
230 | for (i = bit < 32; i < 16; i += 2) | ||
231 | syndrome |= ((ecc_table[i] >> (bit % 32)) & 1) << (i / 2); | ||
232 | |||
233 | return syndrome; | ||
234 | } | ||
235 | |||
236 | /* | ||
237 | * Decode data and ecc syndrome to determine what went wrong | ||
238 | * Note: This can only decode single-bit errors | ||
239 | */ | ||
240 | static void sbe_ecc_decode(u32 cap_high, u32 cap_low, u32 cap_ecc, | ||
241 | int *bad_data_bit, int *bad_ecc_bit) | ||
242 | { | ||
243 | int i; | ||
244 | u8 syndrome; | ||
245 | |||
246 | *bad_data_bit = -1; | ||
247 | *bad_ecc_bit = -1; | ||
248 | |||
249 | /* | ||
250 | * Calculate the ECC of the captured data and XOR it with the captured | ||
251 | * ECC to find an ECC syndrome value we can search for | ||
252 | */ | ||
253 | syndrome = calculate_ecc(cap_high, cap_low) ^ cap_ecc; | ||
254 | |||
255 | /* Check if a data line is stuck... */ | ||
256 | for (i = 0; i < 64; i++) { | ||
257 | if (syndrome == syndrome_from_bit(i)) { | ||
258 | *bad_data_bit = i; | ||
259 | return; | ||
260 | } | ||
261 | } | ||
262 | |||
263 | /* If data is correct, check ECC bits for errors... */ | ||
264 | for (i = 0; i < 8; i++) { | ||
265 | if ((syndrome >> i) & 0x1) { | ||
266 | *bad_ecc_bit = i; | ||
267 | return; | ||
268 | } | ||
269 | } | ||
270 | } | ||
271 | |||
272 | #define make64(high, low) (((u64)(high) << 32) | (low)) | ||
273 | |||
274 | static void fsl_mc_check(struct mem_ctl_info *mci) | ||
275 | { | ||
276 | struct fsl_mc_pdata *pdata = mci->pvt_info; | ||
277 | struct csrow_info *csrow; | ||
278 | u32 bus_width; | ||
279 | u32 err_detect; | ||
280 | u32 syndrome; | ||
281 | u64 err_addr; | ||
282 | u32 pfn; | ||
283 | int row_index; | ||
284 | u32 cap_high; | ||
285 | u32 cap_low; | ||
286 | int bad_data_bit; | ||
287 | int bad_ecc_bit; | ||
288 | |||
289 | err_detect = ddr_in32(pdata->mc_vbase + FSL_MC_ERR_DETECT); | ||
290 | if (!err_detect) | ||
291 | return; | ||
292 | |||
293 | fsl_mc_printk(mci, KERN_ERR, "Err Detect Register: %#8.8x\n", | ||
294 | err_detect); | ||
295 | |||
296 | /* no more processing if not ECC bit errors */ | ||
297 | if (!(err_detect & (DDR_EDE_SBE | DDR_EDE_MBE))) { | ||
298 | ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DETECT, err_detect); | ||
299 | return; | ||
300 | } | ||
301 | |||
302 | syndrome = ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_ECC); | ||
303 | |||
304 | /* Mask off appropriate bits of syndrome based on bus width */ | ||
305 | bus_width = (ddr_in32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG) & | ||
306 | DSC_DBW_MASK) ? 32 : 64; | ||
307 | if (bus_width == 64) | ||
308 | syndrome &= 0xff; | ||
309 | else | ||
310 | syndrome &= 0xffff; | ||
311 | |||
312 | err_addr = make64( | ||
313 | ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_EXT_ADDRESS), | ||
314 | ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_ADDRESS)); | ||
315 | pfn = err_addr >> PAGE_SHIFT; | ||
316 | |||
317 | for (row_index = 0; row_index < mci->nr_csrows; row_index++) { | ||
318 | csrow = mci->csrows[row_index]; | ||
319 | if ((pfn >= csrow->first_page) && (pfn <= csrow->last_page)) | ||
320 | break; | ||
321 | } | ||
322 | |||
323 | cap_high = ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_DATA_HI); | ||
324 | cap_low = ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_DATA_LO); | ||
325 | |||
326 | /* | ||
327 | * Analyze single-bit errors on 64-bit wide buses | ||
328 | * TODO: Add support for 32-bit wide buses | ||
329 | */ | ||
330 | if ((err_detect & DDR_EDE_SBE) && (bus_width == 64)) { | ||
331 | sbe_ecc_decode(cap_high, cap_low, syndrome, | ||
332 | &bad_data_bit, &bad_ecc_bit); | ||
333 | |||
334 | if (bad_data_bit != -1) | ||
335 | fsl_mc_printk(mci, KERN_ERR, | ||
336 | "Faulty Data bit: %d\n", bad_data_bit); | ||
337 | if (bad_ecc_bit != -1) | ||
338 | fsl_mc_printk(mci, KERN_ERR, | ||
339 | "Faulty ECC bit: %d\n", bad_ecc_bit); | ||
340 | |||
341 | fsl_mc_printk(mci, KERN_ERR, | ||
342 | "Expected Data / ECC:\t%#8.8x_%08x / %#2.2x\n", | ||
343 | cap_high ^ (1 << (bad_data_bit - 32)), | ||
344 | cap_low ^ (1 << bad_data_bit), | ||
345 | syndrome ^ (1 << bad_ecc_bit)); | ||
346 | } | ||
347 | |||
348 | fsl_mc_printk(mci, KERN_ERR, | ||
349 | "Captured Data / ECC:\t%#8.8x_%08x / %#2.2x\n", | ||
350 | cap_high, cap_low, syndrome); | ||
351 | fsl_mc_printk(mci, KERN_ERR, "Err addr: %#8.8llx\n", err_addr); | ||
352 | fsl_mc_printk(mci, KERN_ERR, "PFN: %#8.8x\n", pfn); | ||
353 | |||
354 | /* we are out of range */ | ||
355 | if (row_index == mci->nr_csrows) | ||
356 | fsl_mc_printk(mci, KERN_ERR, "PFN out of range!\n"); | ||
357 | |||
358 | if (err_detect & DDR_EDE_SBE) | ||
359 | edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, | ||
360 | pfn, err_addr & ~PAGE_MASK, syndrome, | ||
361 | row_index, 0, -1, | ||
362 | mci->ctl_name, ""); | ||
363 | |||
364 | if (err_detect & DDR_EDE_MBE) | ||
365 | edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, | ||
366 | pfn, err_addr & ~PAGE_MASK, syndrome, | ||
367 | row_index, 0, -1, | ||
368 | mci->ctl_name, ""); | ||
369 | |||
370 | ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DETECT, err_detect); | ||
371 | } | ||
372 | |||
373 | static irqreturn_t fsl_mc_isr(int irq, void *dev_id) | ||
374 | { | ||
375 | struct mem_ctl_info *mci = dev_id; | ||
376 | struct fsl_mc_pdata *pdata = mci->pvt_info; | ||
377 | u32 err_detect; | ||
378 | |||
379 | err_detect = ddr_in32(pdata->mc_vbase + FSL_MC_ERR_DETECT); | ||
380 | if (!err_detect) | ||
381 | return IRQ_NONE; | ||
382 | |||
383 | fsl_mc_check(mci); | ||
384 | |||
385 | return IRQ_HANDLED; | ||
386 | } | ||
387 | |||
388 | static void fsl_ddr_init_csrows(struct mem_ctl_info *mci) | ||
389 | { | ||
390 | struct fsl_mc_pdata *pdata = mci->pvt_info; | ||
391 | struct csrow_info *csrow; | ||
392 | struct dimm_info *dimm; | ||
393 | u32 sdram_ctl; | ||
394 | u32 sdtype; | ||
395 | enum mem_type mtype; | ||
396 | u32 cs_bnds; | ||
397 | int index; | ||
398 | |||
399 | sdram_ctl = ddr_in32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG); | ||
400 | |||
401 | sdtype = sdram_ctl & DSC_SDTYPE_MASK; | ||
402 | if (sdram_ctl & DSC_RD_EN) { | ||
403 | switch (sdtype) { | ||
404 | case 0x02000000: | ||
405 | mtype = MEM_RDDR; | ||
406 | break; | ||
407 | case 0x03000000: | ||
408 | mtype = MEM_RDDR2; | ||
409 | break; | ||
410 | case 0x07000000: | ||
411 | mtype = MEM_RDDR3; | ||
412 | break; | ||
413 | case 0x05000000: | ||
414 | mtype = MEM_RDDR4; | ||
415 | break; | ||
416 | default: | ||
417 | mtype = MEM_UNKNOWN; | ||
418 | break; | ||
419 | } | ||
420 | } else { | ||
421 | switch (sdtype) { | ||
422 | case 0x02000000: | ||
423 | mtype = MEM_DDR; | ||
424 | break; | ||
425 | case 0x03000000: | ||
426 | mtype = MEM_DDR2; | ||
427 | break; | ||
428 | case 0x07000000: | ||
429 | mtype = MEM_DDR3; | ||
430 | break; | ||
431 | case 0x05000000: | ||
432 | mtype = MEM_DDR4; | ||
433 | break; | ||
434 | default: | ||
435 | mtype = MEM_UNKNOWN; | ||
436 | break; | ||
437 | } | ||
438 | } | ||
439 | |||
440 | for (index = 0; index < mci->nr_csrows; index++) { | ||
441 | u32 start; | ||
442 | u32 end; | ||
443 | |||
444 | csrow = mci->csrows[index]; | ||
445 | dimm = csrow->channels[0]->dimm; | ||
446 | |||
447 | cs_bnds = ddr_in32(pdata->mc_vbase + FSL_MC_CS_BNDS_0 + | ||
448 | (index * FSL_MC_CS_BNDS_OFS)); | ||
449 | |||
450 | start = (cs_bnds & 0xffff0000) >> 16; | ||
451 | end = (cs_bnds & 0x0000ffff); | ||
452 | |||
453 | if (start == end) | ||
454 | continue; /* not populated */ | ||
455 | |||
456 | start <<= (24 - PAGE_SHIFT); | ||
457 | end <<= (24 - PAGE_SHIFT); | ||
458 | end |= (1 << (24 - PAGE_SHIFT)) - 1; | ||
459 | |||
460 | csrow->first_page = start; | ||
461 | csrow->last_page = end; | ||
462 | |||
463 | dimm->nr_pages = end + 1 - start; | ||
464 | dimm->grain = 8; | ||
465 | dimm->mtype = mtype; | ||
466 | dimm->dtype = DEV_UNKNOWN; | ||
467 | if (sdram_ctl & DSC_X32_EN) | ||
468 | dimm->dtype = DEV_X32; | ||
469 | dimm->edac_mode = EDAC_SECDED; | ||
470 | } | ||
471 | } | ||
472 | |||
473 | int fsl_mc_err_probe(struct platform_device *op) | ||
474 | { | ||
475 | struct mem_ctl_info *mci; | ||
476 | struct edac_mc_layer layers[2]; | ||
477 | struct fsl_mc_pdata *pdata; | ||
478 | struct resource r; | ||
479 | u32 sdram_ctl; | ||
480 | int res; | ||
481 | |||
482 | if (!devres_open_group(&op->dev, fsl_mc_err_probe, GFP_KERNEL)) | ||
483 | return -ENOMEM; | ||
484 | |||
485 | layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; | ||
486 | layers[0].size = 4; | ||
487 | layers[0].is_virt_csrow = true; | ||
488 | layers[1].type = EDAC_MC_LAYER_CHANNEL; | ||
489 | layers[1].size = 1; | ||
490 | layers[1].is_virt_csrow = false; | ||
491 | mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), layers, | ||
492 | sizeof(*pdata)); | ||
493 | if (!mci) { | ||
494 | devres_release_group(&op->dev, fsl_mc_err_probe); | ||
495 | return -ENOMEM; | ||
496 | } | ||
497 | |||
498 | pdata = mci->pvt_info; | ||
499 | pdata->name = "fsl_mc_err"; | ||
500 | mci->pdev = &op->dev; | ||
501 | pdata->edac_idx = edac_mc_idx++; | ||
502 | dev_set_drvdata(mci->pdev, mci); | ||
503 | mci->ctl_name = pdata->name; | ||
504 | mci->dev_name = pdata->name; | ||
505 | |||
506 | /* | ||
507 | * Get the endianness of DDR controller registers. | ||
508 | * Default is big endian. | ||
509 | */ | ||
510 | little_endian = of_property_read_bool(op->dev.of_node, "little-endian"); | ||
511 | |||
512 | res = of_address_to_resource(op->dev.of_node, 0, &r); | ||
513 | if (res) { | ||
514 | pr_err("%s: Unable to get resource for MC err regs\n", | ||
515 | __func__); | ||
516 | goto err; | ||
517 | } | ||
518 | |||
519 | if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r), | ||
520 | pdata->name)) { | ||
521 | pr_err("%s: Error while requesting mem region\n", | ||
522 | __func__); | ||
523 | res = -EBUSY; | ||
524 | goto err; | ||
525 | } | ||
526 | |||
527 | pdata->mc_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r)); | ||
528 | if (!pdata->mc_vbase) { | ||
529 | pr_err("%s: Unable to setup MC err regs\n", __func__); | ||
530 | res = -ENOMEM; | ||
531 | goto err; | ||
532 | } | ||
533 | |||
534 | sdram_ctl = ddr_in32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG); | ||
535 | if (!(sdram_ctl & DSC_ECC_EN)) { | ||
536 | /* no ECC */ | ||
537 | pr_warn("%s: No ECC DIMMs discovered\n", __func__); | ||
538 | res = -ENODEV; | ||
539 | goto err; | ||
540 | } | ||
541 | |||
542 | edac_dbg(3, "init mci\n"); | ||
543 | mci->mtype_cap = MEM_FLAG_DDR | MEM_FLAG_RDDR | | ||
544 | MEM_FLAG_DDR2 | MEM_FLAG_RDDR2 | | ||
545 | MEM_FLAG_DDR3 | MEM_FLAG_RDDR3 | | ||
546 | MEM_FLAG_DDR4 | MEM_FLAG_RDDR4; | ||
547 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; | ||
548 | mci->edac_cap = EDAC_FLAG_SECDED; | ||
549 | mci->mod_name = EDAC_MOD_STR; | ||
550 | |||
551 | if (edac_op_state == EDAC_OPSTATE_POLL) | ||
552 | mci->edac_check = fsl_mc_check; | ||
553 | |||
554 | mci->ctl_page_to_phys = NULL; | ||
555 | |||
556 | mci->scrub_mode = SCRUB_SW_SRC; | ||
557 | |||
558 | fsl_ddr_init_csrows(mci); | ||
559 | |||
560 | /* store the original error disable bits */ | ||
561 | orig_ddr_err_disable = ddr_in32(pdata->mc_vbase + FSL_MC_ERR_DISABLE); | ||
562 | ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DISABLE, 0); | ||
563 | |||
564 | /* clear all error bits */ | ||
565 | ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DETECT, ~0); | ||
566 | |||
567 | res = edac_mc_add_mc_with_groups(mci, fsl_ddr_dev_groups); | ||
568 | if (res) { | ||
569 | edac_dbg(3, "failed edac_mc_add_mc()\n"); | ||
570 | goto err; | ||
571 | } | ||
572 | |||
573 | if (edac_op_state == EDAC_OPSTATE_INT) { | ||
574 | ddr_out32(pdata->mc_vbase + FSL_MC_ERR_INT_EN, | ||
575 | DDR_EIE_MBEE | DDR_EIE_SBEE); | ||
576 | |||
577 | /* store the original error management threshold */ | ||
578 | orig_ddr_err_sbe = ddr_in32(pdata->mc_vbase + | ||
579 | FSL_MC_ERR_SBE) & 0xff0000; | ||
580 | |||
581 | /* set threshold to 1 error per interrupt */ | ||
582 | ddr_out32(pdata->mc_vbase + FSL_MC_ERR_SBE, 0x10000); | ||
583 | |||
584 | /* register interrupts */ | ||
585 | pdata->irq = platform_get_irq(op, 0); | ||
586 | res = devm_request_irq(&op->dev, pdata->irq, | ||
587 | fsl_mc_isr, | ||
588 | IRQF_SHARED, | ||
589 | "[EDAC] MC err", mci); | ||
590 | if (res < 0) { | ||
591 | pr_err("%s: Unable to request irq %d for FSL DDR DRAM ERR\n", | ||
592 | __func__, pdata->irq); | ||
593 | res = -ENODEV; | ||
594 | goto err2; | ||
595 | } | ||
596 | |||
597 | pr_info(EDAC_MOD_STR " acquired irq %d for MC\n", | ||
598 | pdata->irq); | ||
599 | } | ||
600 | |||
601 | devres_remove_group(&op->dev, fsl_mc_err_probe); | ||
602 | edac_dbg(3, "success\n"); | ||
603 | pr_info(EDAC_MOD_STR " MC err registered\n"); | ||
604 | |||
605 | return 0; | ||
606 | |||
607 | err2: | ||
608 | edac_mc_del_mc(&op->dev); | ||
609 | err: | ||
610 | devres_release_group(&op->dev, fsl_mc_err_probe); | ||
611 | edac_mc_free(mci); | ||
612 | return res; | ||
613 | } | ||
614 | |||
615 | int fsl_mc_err_remove(struct platform_device *op) | ||
616 | { | ||
617 | struct mem_ctl_info *mci = dev_get_drvdata(&op->dev); | ||
618 | struct fsl_mc_pdata *pdata = mci->pvt_info; | ||
619 | |||
620 | edac_dbg(0, "\n"); | ||
621 | |||
622 | if (edac_op_state == EDAC_OPSTATE_INT) { | ||
623 | ddr_out32(pdata->mc_vbase + FSL_MC_ERR_INT_EN, 0); | ||
624 | } | ||
625 | |||
626 | ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DISABLE, | ||
627 | orig_ddr_err_disable); | ||
628 | ddr_out32(pdata->mc_vbase + FSL_MC_ERR_SBE, orig_ddr_err_sbe); | ||
629 | |||
630 | edac_mc_del_mc(&op->dev); | ||
631 | edac_mc_free(mci); | ||
632 | return 0; | ||
633 | } | ||
diff --git a/drivers/edac/fsl_ddr_edac.h b/drivers/edac/fsl_ddr_edac.h new file mode 100644 index 000000000000..4ccee292eff1 --- /dev/null +++ b/drivers/edac/fsl_ddr_edac.h | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | * Freescale Memory Controller kernel module | ||
3 | * | ||
4 | * Support Power-based SoCs including MPC85xx, MPC86xx, MPC83xx and | ||
5 | * ARM-based Layerscape SoCs including LS2xxx. Originally split | ||
6 | * out from mpc85xx_edac EDAC driver. | ||
7 | * | ||
8 | * Author: Dave Jiang <djiang@mvista.com> | ||
9 | * | ||
10 | * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under | ||
11 | * the terms of the GNU General Public License version 2. This program | ||
12 | * is licensed "as is" without any warranty of any kind, whether express | ||
13 | * or implied. | ||
14 | * | ||
15 | */ | ||
16 | #ifndef _FSL_DDR_EDAC_H_ | ||
17 | #define _FSL_DDR_EDAC_H_ | ||
18 | |||
19 | #define fsl_mc_printk(mci, level, fmt, arg...) \ | ||
20 | edac_mc_chipset_printk(mci, level, "FSL_DDR", fmt, ##arg) | ||
21 | |||
22 | /* | ||
23 | * DRAM error defines | ||
24 | */ | ||
25 | |||
26 | /* DDR_SDRAM_CFG */ | ||
27 | #define FSL_MC_DDR_SDRAM_CFG 0x0110 | ||
28 | #define FSL_MC_CS_BNDS_0 0x0000 | ||
29 | #define FSL_MC_CS_BNDS_OFS 0x0008 | ||
30 | |||
31 | #define FSL_MC_DATA_ERR_INJECT_HI 0x0e00 | ||
32 | #define FSL_MC_DATA_ERR_INJECT_LO 0x0e04 | ||
33 | #define FSL_MC_ECC_ERR_INJECT 0x0e08 | ||
34 | #define FSL_MC_CAPTURE_DATA_HI 0x0e20 | ||
35 | #define FSL_MC_CAPTURE_DATA_LO 0x0e24 | ||
36 | #define FSL_MC_CAPTURE_ECC 0x0e28 | ||
37 | #define FSL_MC_ERR_DETECT 0x0e40 | ||
38 | #define FSL_MC_ERR_DISABLE 0x0e44 | ||
39 | #define FSL_MC_ERR_INT_EN 0x0e48 | ||
40 | #define FSL_MC_CAPTURE_ATRIBUTES 0x0e4c | ||
41 | #define FSL_MC_CAPTURE_ADDRESS 0x0e50 | ||
42 | #define FSL_MC_CAPTURE_EXT_ADDRESS 0x0e54 | ||
43 | #define FSL_MC_ERR_SBE 0x0e58 | ||
44 | |||
45 | #define DSC_MEM_EN 0x80000000 | ||
46 | #define DSC_ECC_EN 0x20000000 | ||
47 | #define DSC_RD_EN 0x10000000 | ||
48 | #define DSC_DBW_MASK 0x00180000 | ||
49 | #define DSC_DBW_32 0x00080000 | ||
50 | #define DSC_DBW_64 0x00000000 | ||
51 | |||
52 | #define DSC_SDTYPE_MASK 0x07000000 | ||
53 | #define DSC_X32_EN 0x00000020 | ||
54 | |||
55 | /* Err_Int_En */ | ||
56 | #define DDR_EIE_MSEE 0x1 /* memory select */ | ||
57 | #define DDR_EIE_SBEE 0x4 /* single-bit ECC error */ | ||
58 | #define DDR_EIE_MBEE 0x8 /* multi-bit ECC error */ | ||
59 | |||
60 | /* Err_Detect */ | ||
61 | #define DDR_EDE_MSE 0x1 /* memory select */ | ||
62 | #define DDR_EDE_SBE 0x4 /* single-bit ECC error */ | ||
63 | #define DDR_EDE_MBE 0x8 /* multi-bit ECC error */ | ||
64 | #define DDR_EDE_MME 0x80000000 /* multiple memory errors */ | ||
65 | |||
66 | /* Err_Disable */ | ||
67 | #define DDR_EDI_MSED 0x1 /* memory select disable */ | ||
68 | #define DDR_EDI_SBED 0x4 /* single-bit ECC error disable */ | ||
69 | #define DDR_EDI_MBED 0x8 /* multi-bit ECC error disable */ | ||
70 | |||
71 | struct fsl_mc_pdata { | ||
72 | char *name; | ||
73 | int edac_idx; | ||
74 | void __iomem *mc_vbase; | ||
75 | int irq; | ||
76 | }; | ||
77 | int fsl_mc_err_probe(struct platform_device *op); | ||
78 | int fsl_mc_err_remove(struct platform_device *op); | ||
79 | #endif | ||
diff --git a/drivers/edac/layerscape_edac.c b/drivers/edac/layerscape_edac.c new file mode 100644 index 000000000000..6c59d897ad12 --- /dev/null +++ b/drivers/edac/layerscape_edac.c | |||
@@ -0,0 +1,73 @@ | |||
1 | /* | ||
2 | * Freescale Memory Controller kernel module | ||
3 | * | ||
4 | * Author: York Sun <york.sun@nxp.com> | ||
5 | * | ||
6 | * Copyright 2016 NXP Semiconductor | ||
7 | * | ||
8 | * Derived from mpc85xx_edac.c | ||
9 | * Author: Dave Jiang <djiang@mvista.com> | ||
10 | * | ||
11 | * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under | ||
12 | * the terms of the GNU General Public License version 2. This program | ||
13 | * is licensed "as is" without any warranty of any kind, whether express | ||
14 | * or implied. | ||
15 | */ | ||
16 | |||
17 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
18 | |||
19 | #include "edac_core.h" | ||
20 | #include "fsl_ddr_edac.h" | ||
21 | |||
22 | static const struct of_device_id fsl_ddr_mc_err_of_match[] = { | ||
23 | { .compatible = "fsl,qoriq-memory-controller", }, | ||
24 | {}, | ||
25 | }; | ||
26 | MODULE_DEVICE_TABLE(of, fsl_ddr_mc_err_of_match); | ||
27 | |||
28 | static struct platform_driver fsl_ddr_mc_err_driver = { | ||
29 | .probe = fsl_mc_err_probe, | ||
30 | .remove = fsl_mc_err_remove, | ||
31 | .driver = { | ||
32 | .name = "fsl_ddr_mc_err", | ||
33 | .of_match_table = fsl_ddr_mc_err_of_match, | ||
34 | }, | ||
35 | }; | ||
36 | |||
37 | static int __init fsl_ddr_mc_init(void) | ||
38 | { | ||
39 | int res; | ||
40 | |||
41 | /* make sure error reporting method is sane */ | ||
42 | switch (edac_op_state) { | ||
43 | case EDAC_OPSTATE_POLL: | ||
44 | case EDAC_OPSTATE_INT: | ||
45 | break; | ||
46 | default: | ||
47 | edac_op_state = EDAC_OPSTATE_INT; | ||
48 | break; | ||
49 | } | ||
50 | |||
51 | res = platform_driver_register(&fsl_ddr_mc_err_driver); | ||
52 | if (res) { | ||
53 | pr_err("MC fails to register\n"); | ||
54 | return res; | ||
55 | } | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | module_init(fsl_ddr_mc_init); | ||
61 | |||
62 | static void __exit fsl_ddr_mc_exit(void) | ||
63 | { | ||
64 | platform_driver_unregister(&fsl_ddr_mc_err_driver); | ||
65 | } | ||
66 | |||
67 | module_exit(fsl_ddr_mc_exit); | ||
68 | |||
69 | MODULE_LICENSE("GPL"); | ||
70 | MODULE_AUTHOR("NXP Semiconductor"); | ||
71 | module_param(edac_op_state, int, 0444); | ||
72 | MODULE_PARM_DESC(edac_op_state, | ||
73 | "EDAC Error Reporting state: 0=Poll, 2=Interrupt"); | ||
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index ca63d0da8889..ff0567526ee3 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c | |||
@@ -27,15 +27,12 @@ | |||
27 | #include "edac_module.h" | 27 | #include "edac_module.h" |
28 | #include "edac_core.h" | 28 | #include "edac_core.h" |
29 | #include "mpc85xx_edac.h" | 29 | #include "mpc85xx_edac.h" |
30 | #include "fsl_ddr_edac.h" | ||
30 | 31 | ||
31 | static int edac_dev_idx; | 32 | static int edac_dev_idx; |
32 | #ifdef CONFIG_PCI | 33 | #ifdef CONFIG_PCI |
33 | static int edac_pci_idx; | 34 | static int edac_pci_idx; |
34 | #endif | 35 | #endif |
35 | static int edac_mc_idx; | ||
36 | |||
37 | static u32 orig_ddr_err_disable; | ||
38 | static u32 orig_ddr_err_sbe; | ||
39 | 36 | ||
40 | /* | 37 | /* |
41 | * PCI Err defines | 38 | * PCI Err defines |
@@ -46,103 +43,6 @@ static u32 orig_pci_err_en; | |||
46 | #endif | 43 | #endif |
47 | 44 | ||
48 | static u32 orig_l2_err_disable; | 45 | static u32 orig_l2_err_disable; |
49 | #ifdef CONFIG_FSL_SOC_BOOKE | ||
50 | static u32 orig_hid1[2]; | ||
51 | #endif | ||
52 | |||
53 | /************************ MC SYSFS parts ***********************************/ | ||
54 | |||
55 | #define to_mci(k) container_of(k, struct mem_ctl_info, dev) | ||
56 | |||
57 | static ssize_t mpc85xx_mc_inject_data_hi_show(struct device *dev, | ||
58 | struct device_attribute *mattr, | ||
59 | char *data) | ||
60 | { | ||
61 | struct mem_ctl_info *mci = to_mci(dev); | ||
62 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
63 | return sprintf(data, "0x%08x", | ||
64 | in_be32(pdata->mc_vbase + | ||
65 | MPC85XX_MC_DATA_ERR_INJECT_HI)); | ||
66 | } | ||
67 | |||
68 | static ssize_t mpc85xx_mc_inject_data_lo_show(struct device *dev, | ||
69 | struct device_attribute *mattr, | ||
70 | char *data) | ||
71 | { | ||
72 | struct mem_ctl_info *mci = to_mci(dev); | ||
73 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
74 | return sprintf(data, "0x%08x", | ||
75 | in_be32(pdata->mc_vbase + | ||
76 | MPC85XX_MC_DATA_ERR_INJECT_LO)); | ||
77 | } | ||
78 | |||
79 | static ssize_t mpc85xx_mc_inject_ctrl_show(struct device *dev, | ||
80 | struct device_attribute *mattr, | ||
81 | char *data) | ||
82 | { | ||
83 | struct mem_ctl_info *mci = to_mci(dev); | ||
84 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
85 | return sprintf(data, "0x%08x", | ||
86 | in_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT)); | ||
87 | } | ||
88 | |||
89 | static ssize_t mpc85xx_mc_inject_data_hi_store(struct device *dev, | ||
90 | struct device_attribute *mattr, | ||
91 | const char *data, size_t count) | ||
92 | { | ||
93 | struct mem_ctl_info *mci = to_mci(dev); | ||
94 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
95 | if (isdigit(*data)) { | ||
96 | out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_HI, | ||
97 | simple_strtoul(data, NULL, 0)); | ||
98 | return count; | ||
99 | } | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static ssize_t mpc85xx_mc_inject_data_lo_store(struct device *dev, | ||
104 | struct device_attribute *mattr, | ||
105 | const char *data, size_t count) | ||
106 | { | ||
107 | struct mem_ctl_info *mci = to_mci(dev); | ||
108 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
109 | if (isdigit(*data)) { | ||
110 | out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_LO, | ||
111 | simple_strtoul(data, NULL, 0)); | ||
112 | return count; | ||
113 | } | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | static ssize_t mpc85xx_mc_inject_ctrl_store(struct device *dev, | ||
118 | struct device_attribute *mattr, | ||
119 | const char *data, size_t count) | ||
120 | { | ||
121 | struct mem_ctl_info *mci = to_mci(dev); | ||
122 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
123 | if (isdigit(*data)) { | ||
124 | out_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT, | ||
125 | simple_strtoul(data, NULL, 0)); | ||
126 | return count; | ||
127 | } | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | DEVICE_ATTR(inject_data_hi, S_IRUGO | S_IWUSR, | ||
132 | mpc85xx_mc_inject_data_hi_show, mpc85xx_mc_inject_data_hi_store); | ||
133 | DEVICE_ATTR(inject_data_lo, S_IRUGO | S_IWUSR, | ||
134 | mpc85xx_mc_inject_data_lo_show, mpc85xx_mc_inject_data_lo_store); | ||
135 | DEVICE_ATTR(inject_ctrl, S_IRUGO | S_IWUSR, | ||
136 | mpc85xx_mc_inject_ctrl_show, mpc85xx_mc_inject_ctrl_store); | ||
137 | |||
138 | static struct attribute *mpc85xx_dev_attrs[] = { | ||
139 | &dev_attr_inject_data_hi.attr, | ||
140 | &dev_attr_inject_data_lo.attr, | ||
141 | &dev_attr_inject_ctrl.attr, | ||
142 | NULL | ||
143 | }; | ||
144 | |||
145 | ATTRIBUTE_GROUPS(mpc85xx_dev); | ||
146 | 46 | ||
147 | /**************************** PCI Err device ***************************/ | 47 | /**************************** PCI Err device ***************************/ |
148 | #ifdef CONFIG_PCI | 48 | #ifdef CONFIG_PCI |
@@ -160,18 +60,18 @@ static void mpc85xx_pci_check(struct edac_pci_ctl_info *pci) | |||
160 | return; | 60 | return; |
161 | } | 61 | } |
162 | 62 | ||
163 | printk(KERN_ERR "PCI error(s) detected\n"); | 63 | pr_err("PCI error(s) detected\n"); |
164 | printk(KERN_ERR "PCI/X ERR_DR register: %#08x\n", err_detect); | 64 | pr_err("PCI/X ERR_DR register: %#08x\n", err_detect); |
165 | 65 | ||
166 | printk(KERN_ERR "PCI/X ERR_ATTRIB register: %#08x\n", | 66 | pr_err("PCI/X ERR_ATTRIB register: %#08x\n", |
167 | in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ATTRIB)); | 67 | in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ATTRIB)); |
168 | printk(KERN_ERR "PCI/X ERR_ADDR register: %#08x\n", | 68 | pr_err("PCI/X ERR_ADDR register: %#08x\n", |
169 | in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR)); | 69 | in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR)); |
170 | printk(KERN_ERR "PCI/X ERR_EXT_ADDR register: %#08x\n", | 70 | pr_err("PCI/X ERR_EXT_ADDR register: %#08x\n", |
171 | in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EXT_ADDR)); | 71 | in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EXT_ADDR)); |
172 | printk(KERN_ERR "PCI/X ERR_DL register: %#08x\n", | 72 | pr_err("PCI/X ERR_DL register: %#08x\n", |
173 | in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DL)); | 73 | in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DL)); |
174 | printk(KERN_ERR "PCI/X ERR_DH register: %#08x\n", | 74 | pr_err("PCI/X ERR_DH register: %#08x\n", |
175 | in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DH)); | 75 | in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DH)); |
176 | 76 | ||
177 | /* clear error bits */ | 77 | /* clear error bits */ |
@@ -187,14 +87,14 @@ static void mpc85xx_pci_check(struct edac_pci_ctl_info *pci) | |||
187 | static void mpc85xx_pcie_check(struct edac_pci_ctl_info *pci) | 87 | static void mpc85xx_pcie_check(struct edac_pci_ctl_info *pci) |
188 | { | 88 | { |
189 | struct mpc85xx_pci_pdata *pdata = pci->pvt_info; | 89 | struct mpc85xx_pci_pdata *pdata = pci->pvt_info; |
190 | u32 err_detect; | 90 | u32 err_detect, err_cap_stat; |
191 | 91 | ||
192 | err_detect = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR); | 92 | err_detect = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR); |
93 | err_cap_stat = in_be32(pdata->pci_vbase + MPC85XX_PCI_GAS_TIMR); | ||
193 | 94 | ||
194 | pr_err("PCIe error(s) detected\n"); | 95 | pr_err("PCIe error(s) detected\n"); |
195 | pr_err("PCIe ERR_DR register: 0x%08x\n", err_detect); | 96 | pr_err("PCIe ERR_DR register: 0x%08x\n", err_detect); |
196 | pr_err("PCIe ERR_CAP_STAT register: 0x%08x\n", | 97 | pr_err("PCIe ERR_CAP_STAT register: 0x%08x\n", err_cap_stat); |
197 | in_be32(pdata->pci_vbase + MPC85XX_PCI_GAS_TIMR)); | ||
198 | pr_err("PCIe ERR_CAP_R0 register: 0x%08x\n", | 98 | pr_err("PCIe ERR_CAP_R0 register: 0x%08x\n", |
199 | in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R0)); | 99 | in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R0)); |
200 | pr_err("PCIe ERR_CAP_R1 register: 0x%08x\n", | 100 | pr_err("PCIe ERR_CAP_R1 register: 0x%08x\n", |
@@ -206,6 +106,9 @@ static void mpc85xx_pcie_check(struct edac_pci_ctl_info *pci) | |||
206 | 106 | ||
207 | /* clear error bits */ | 107 | /* clear error bits */ |
208 | out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, err_detect); | 108 | out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, err_detect); |
109 | |||
110 | /* reset error capture */ | ||
111 | out_be32(pdata->pci_vbase + MPC85XX_PCI_GAS_TIMR, err_cap_stat | 0x1); | ||
209 | } | 112 | } |
210 | 113 | ||
211 | static int mpc85xx_pcie_find_capability(struct device_node *np) | 114 | static int mpc85xx_pcie_find_capability(struct device_node *np) |
@@ -267,7 +170,6 @@ static int mpc85xx_pci_err_probe(struct platform_device *op) | |||
267 | 170 | ||
268 | pdata = pci->pvt_info; | 171 | pdata = pci->pvt_info; |
269 | pdata->name = "mpc85xx_pci_err"; | 172 | pdata->name = "mpc85xx_pci_err"; |
270 | pdata->irq = NO_IRQ; | ||
271 | 173 | ||
272 | plat_data = op->dev.platform_data; | 174 | plat_data = op->dev.platform_data; |
273 | if (!plat_data) { | 175 | if (!plat_data) { |
@@ -297,8 +199,7 @@ static int mpc85xx_pci_err_probe(struct platform_device *op) | |||
297 | 199 | ||
298 | res = of_address_to_resource(of_node, 0, &r); | 200 | res = of_address_to_resource(of_node, 0, &r); |
299 | if (res) { | 201 | if (res) { |
300 | printk(KERN_ERR "%s: Unable to get resource for " | 202 | pr_err("%s: Unable to get resource for PCI err regs\n", __func__); |
301 | "PCI err regs\n", __func__); | ||
302 | goto err; | 203 | goto err; |
303 | } | 204 | } |
304 | 205 | ||
@@ -307,15 +208,14 @@ static int mpc85xx_pci_err_probe(struct platform_device *op) | |||
307 | 208 | ||
308 | if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r), | 209 | if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r), |
309 | pdata->name)) { | 210 | pdata->name)) { |
310 | printk(KERN_ERR "%s: Error while requesting mem region\n", | 211 | pr_err("%s: Error while requesting mem region\n", __func__); |
311 | __func__); | ||
312 | res = -EBUSY; | 212 | res = -EBUSY; |
313 | goto err; | 213 | goto err; |
314 | } | 214 | } |
315 | 215 | ||
316 | pdata->pci_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r)); | 216 | pdata->pci_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r)); |
317 | if (!pdata->pci_vbase) { | 217 | if (!pdata->pci_vbase) { |
318 | printk(KERN_ERR "%s: Unable to setup PCI err regs\n", __func__); | 218 | pr_err("%s: Unable to setup PCI err regs\n", __func__); |
319 | res = -ENOMEM; | 219 | res = -ENOMEM; |
320 | goto err; | 220 | goto err; |
321 | } | 221 | } |
@@ -344,6 +244,9 @@ static int mpc85xx_pci_err_probe(struct platform_device *op) | |||
344 | /* clear error bits */ | 244 | /* clear error bits */ |
345 | out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, ~0); | 245 | out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, ~0); |
346 | 246 | ||
247 | /* reset error capture */ | ||
248 | out_be32(pdata->pci_vbase + MPC85XX_PCI_GAS_TIMR, 0x1); | ||
249 | |||
347 | if (edac_pci_add_device(pci, pdata->edac_idx) > 0) { | 250 | if (edac_pci_add_device(pci, pdata->edac_idx) > 0) { |
348 | edac_dbg(3, "failed edac_pci_add_device()\n"); | 251 | edac_dbg(3, "failed edac_pci_add_device()\n"); |
349 | goto err; | 252 | goto err; |
@@ -356,15 +259,14 @@ static int mpc85xx_pci_err_probe(struct platform_device *op) | |||
356 | IRQF_SHARED, | 259 | IRQF_SHARED, |
357 | "[EDAC] PCI err", pci); | 260 | "[EDAC] PCI err", pci); |
358 | if (res < 0) { | 261 | if (res < 0) { |
359 | printk(KERN_ERR | 262 | pr_err("%s: Unable to request irq %d for MPC85xx PCI err\n", |
360 | "%s: Unable to request irq %d for " | 263 | __func__, pdata->irq); |
361 | "MPC85xx PCI err\n", __func__, pdata->irq); | ||
362 | irq_dispose_mapping(pdata->irq); | 264 | irq_dispose_mapping(pdata->irq); |
363 | res = -ENODEV; | 265 | res = -ENODEV; |
364 | goto err2; | 266 | goto err2; |
365 | } | 267 | } |
366 | 268 | ||
367 | printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for PCI Err\n", | 269 | pr_info(EDAC_MOD_STR " acquired irq %d for PCI Err\n", |
368 | pdata->irq); | 270 | pdata->irq); |
369 | } | 271 | } |
370 | 272 | ||
@@ -386,7 +288,7 @@ static int mpc85xx_pci_err_probe(struct platform_device *op) | |||
386 | 288 | ||
387 | devres_remove_group(&op->dev, mpc85xx_pci_err_probe); | 289 | devres_remove_group(&op->dev, mpc85xx_pci_err_probe); |
388 | edac_dbg(3, "success\n"); | 290 | edac_dbg(3, "success\n"); |
389 | printk(KERN_INFO EDAC_MOD_STR " PCI err registered\n"); | 291 | pr_info(EDAC_MOD_STR " PCI err registered\n"); |
390 | 292 | ||
391 | return 0; | 293 | return 0; |
392 | 294 | ||
@@ -529,17 +431,17 @@ static void mpc85xx_l2_check(struct edac_device_ctl_info *edac_dev) | |||
529 | if (!(err_detect & L2_EDE_MASK)) | 431 | if (!(err_detect & L2_EDE_MASK)) |
530 | return; | 432 | return; |
531 | 433 | ||
532 | printk(KERN_ERR "ECC Error in CPU L2 cache\n"); | 434 | pr_err("ECC Error in CPU L2 cache\n"); |
533 | printk(KERN_ERR "L2 Error Detect Register: 0x%08x\n", err_detect); | 435 | pr_err("L2 Error Detect Register: 0x%08x\n", err_detect); |
534 | printk(KERN_ERR "L2 Error Capture Data High Register: 0x%08x\n", | 436 | pr_err("L2 Error Capture Data High Register: 0x%08x\n", |
535 | in_be32(pdata->l2_vbase + MPC85XX_L2_CAPTDATAHI)); | 437 | in_be32(pdata->l2_vbase + MPC85XX_L2_CAPTDATAHI)); |
536 | printk(KERN_ERR "L2 Error Capture Data Lo Register: 0x%08x\n", | 438 | pr_err("L2 Error Capture Data Lo Register: 0x%08x\n", |
537 | in_be32(pdata->l2_vbase + MPC85XX_L2_CAPTDATALO)); | 439 | in_be32(pdata->l2_vbase + MPC85XX_L2_CAPTDATALO)); |
538 | printk(KERN_ERR "L2 Error Syndrome Register: 0x%08x\n", | 440 | pr_err("L2 Error Syndrome Register: 0x%08x\n", |
539 | in_be32(pdata->l2_vbase + MPC85XX_L2_CAPTECC)); | 441 | in_be32(pdata->l2_vbase + MPC85XX_L2_CAPTECC)); |
540 | printk(KERN_ERR "L2 Error Attributes Capture Register: 0x%08x\n", | 442 | pr_err("L2 Error Attributes Capture Register: 0x%08x\n", |
541 | in_be32(pdata->l2_vbase + MPC85XX_L2_ERRATTR)); | 443 | in_be32(pdata->l2_vbase + MPC85XX_L2_ERRATTR)); |
542 | printk(KERN_ERR "L2 Error Address Capture Register: 0x%08x\n", | 444 | pr_err("L2 Error Address Capture Register: 0x%08x\n", |
543 | in_be32(pdata->l2_vbase + MPC85XX_L2_ERRADDR)); | 445 | in_be32(pdata->l2_vbase + MPC85XX_L2_ERRADDR)); |
544 | 446 | ||
545 | /* clear error detect register */ | 447 | /* clear error detect register */ |
@@ -588,7 +490,6 @@ static int mpc85xx_l2_err_probe(struct platform_device *op) | |||
588 | 490 | ||
589 | pdata = edac_dev->pvt_info; | 491 | pdata = edac_dev->pvt_info; |
590 | pdata->name = "mpc85xx_l2_err"; | 492 | pdata->name = "mpc85xx_l2_err"; |
591 | pdata->irq = NO_IRQ; | ||
592 | edac_dev->dev = &op->dev; | 493 | edac_dev->dev = &op->dev; |
593 | dev_set_drvdata(edac_dev->dev, edac_dev); | 494 | dev_set_drvdata(edac_dev->dev, edac_dev); |
594 | edac_dev->ctl_name = pdata->name; | 495 | edac_dev->ctl_name = pdata->name; |
@@ -596,8 +497,7 @@ static int mpc85xx_l2_err_probe(struct platform_device *op) | |||
596 | 497 | ||
597 | res = of_address_to_resource(op->dev.of_node, 0, &r); | 498 | res = of_address_to_resource(op->dev.of_node, 0, &r); |
598 | if (res) { | 499 | if (res) { |
599 | printk(KERN_ERR "%s: Unable to get resource for " | 500 | pr_err("%s: Unable to get resource for L2 err regs\n", __func__); |
600 | "L2 err regs\n", __func__); | ||
601 | goto err; | 501 | goto err; |
602 | } | 502 | } |
603 | 503 | ||
@@ -606,15 +506,14 @@ static int mpc85xx_l2_err_probe(struct platform_device *op) | |||
606 | 506 | ||
607 | if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r), | 507 | if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r), |
608 | pdata->name)) { | 508 | pdata->name)) { |
609 | printk(KERN_ERR "%s: Error while requesting mem region\n", | 509 | pr_err("%s: Error while requesting mem region\n", __func__); |
610 | __func__); | ||
611 | res = -EBUSY; | 510 | res = -EBUSY; |
612 | goto err; | 511 | goto err; |
613 | } | 512 | } |
614 | 513 | ||
615 | pdata->l2_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r)); | 514 | pdata->l2_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r)); |
616 | if (!pdata->l2_vbase) { | 515 | if (!pdata->l2_vbase) { |
617 | printk(KERN_ERR "%s: Unable to setup L2 err regs\n", __func__); | 516 | pr_err("%s: Unable to setup L2 err regs\n", __func__); |
618 | res = -ENOMEM; | 517 | res = -ENOMEM; |
619 | goto err; | 518 | goto err; |
620 | } | 519 | } |
@@ -646,16 +545,14 @@ static int mpc85xx_l2_err_probe(struct platform_device *op) | |||
646 | mpc85xx_l2_isr, IRQF_SHARED, | 545 | mpc85xx_l2_isr, IRQF_SHARED, |
647 | "[EDAC] L2 err", edac_dev); | 546 | "[EDAC] L2 err", edac_dev); |
648 | if (res < 0) { | 547 | if (res < 0) { |
649 | printk(KERN_ERR | 548 | pr_err("%s: Unable to request irq %d for MPC85xx L2 err\n", |
650 | "%s: Unable to request irq %d for " | 549 | __func__, pdata->irq); |
651 | "MPC85xx L2 err\n", __func__, pdata->irq); | ||
652 | irq_dispose_mapping(pdata->irq); | 550 | irq_dispose_mapping(pdata->irq); |
653 | res = -ENODEV; | 551 | res = -ENODEV; |
654 | goto err2; | 552 | goto err2; |
655 | } | 553 | } |
656 | 554 | ||
657 | printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for L2 Err\n", | 555 | pr_info(EDAC_MOD_STR " acquired irq %d for L2 Err\n", pdata->irq); |
658 | pdata->irq); | ||
659 | 556 | ||
660 | edac_dev->op_state = OP_RUNNING_INTERRUPT; | 557 | edac_dev->op_state = OP_RUNNING_INTERRUPT; |
661 | 558 | ||
@@ -665,7 +562,7 @@ static int mpc85xx_l2_err_probe(struct platform_device *op) | |||
665 | devres_remove_group(&op->dev, mpc85xx_l2_err_probe); | 562 | devres_remove_group(&op->dev, mpc85xx_l2_err_probe); |
666 | 563 | ||
667 | edac_dbg(3, "success\n"); | 564 | edac_dbg(3, "success\n"); |
668 | printk(KERN_INFO EDAC_MOD_STR " L2 err registered\n"); | 565 | pr_info(EDAC_MOD_STR " L2 err registered\n"); |
669 | 566 | ||
670 | return 0; | 567 | return 0; |
671 | 568 | ||
@@ -729,466 +626,6 @@ static struct platform_driver mpc85xx_l2_err_driver = { | |||
729 | }, | 626 | }, |
730 | }; | 627 | }; |
731 | 628 | ||
732 | /**************************** MC Err device ***************************/ | ||
733 | |||
734 | /* | ||
735 | * Taken from table 8-55 in the MPC8641 User's Manual and/or 9-61 in the | ||
736 | * MPC8572 User's Manual. Each line represents a syndrome bit column as a | ||
737 | * 64-bit value, but split into an upper and lower 32-bit chunk. The labels | ||
738 | * below correspond to Freescale's manuals. | ||
739 | */ | ||
740 | static unsigned int ecc_table[16] = { | ||
741 | /* MSB LSB */ | ||
742 | /* [0:31] [32:63] */ | ||
743 | 0xf00fe11e, 0xc33c0ff7, /* Syndrome bit 7 */ | ||
744 | 0x00ff00ff, 0x00fff0ff, | ||
745 | 0x0f0f0f0f, 0x0f0fff00, | ||
746 | 0x11113333, 0x7777000f, | ||
747 | 0x22224444, 0x8888222f, | ||
748 | 0x44448888, 0xffff4441, | ||
749 | 0x8888ffff, 0x11118882, | ||
750 | 0xffff1111, 0x22221114, /* Syndrome bit 0 */ | ||
751 | }; | ||
752 | |||
753 | /* | ||
754 | * Calculate the correct ECC value for a 64-bit value specified by high:low | ||
755 | */ | ||
756 | static u8 calculate_ecc(u32 high, u32 low) | ||
757 | { | ||
758 | u32 mask_low; | ||
759 | u32 mask_high; | ||
760 | int bit_cnt; | ||
761 | u8 ecc = 0; | ||
762 | int i; | ||
763 | int j; | ||
764 | |||
765 | for (i = 0; i < 8; i++) { | ||
766 | mask_high = ecc_table[i * 2]; | ||
767 | mask_low = ecc_table[i * 2 + 1]; | ||
768 | bit_cnt = 0; | ||
769 | |||
770 | for (j = 0; j < 32; j++) { | ||
771 | if ((mask_high >> j) & 1) | ||
772 | bit_cnt ^= (high >> j) & 1; | ||
773 | if ((mask_low >> j) & 1) | ||
774 | bit_cnt ^= (low >> j) & 1; | ||
775 | } | ||
776 | |||
777 | ecc |= bit_cnt << i; | ||
778 | } | ||
779 | |||
780 | return ecc; | ||
781 | } | ||
782 | |||
783 | /* | ||
784 | * Create the syndrome code which is generated if the data line specified by | ||
785 | * 'bit' failed. Eg generate an 8-bit codes seen in Table 8-55 in the MPC8641 | ||
786 | * User's Manual and 9-61 in the MPC8572 User's Manual. | ||
787 | */ | ||
788 | static u8 syndrome_from_bit(unsigned int bit) { | ||
789 | int i; | ||
790 | u8 syndrome = 0; | ||
791 | |||
792 | /* | ||
793 | * Cycle through the upper or lower 32-bit portion of each value in | ||
794 | * ecc_table depending on if 'bit' is in the upper or lower half of | ||
795 | * 64-bit data. | ||
796 | */ | ||
797 | for (i = bit < 32; i < 16; i += 2) | ||
798 | syndrome |= ((ecc_table[i] >> (bit % 32)) & 1) << (i / 2); | ||
799 | |||
800 | return syndrome; | ||
801 | } | ||
802 | |||
803 | /* | ||
804 | * Decode data and ecc syndrome to determine what went wrong | ||
805 | * Note: This can only decode single-bit errors | ||
806 | */ | ||
807 | static void sbe_ecc_decode(u32 cap_high, u32 cap_low, u32 cap_ecc, | ||
808 | int *bad_data_bit, int *bad_ecc_bit) | ||
809 | { | ||
810 | int i; | ||
811 | u8 syndrome; | ||
812 | |||
813 | *bad_data_bit = -1; | ||
814 | *bad_ecc_bit = -1; | ||
815 | |||
816 | /* | ||
817 | * Calculate the ECC of the captured data and XOR it with the captured | ||
818 | * ECC to find an ECC syndrome value we can search for | ||
819 | */ | ||
820 | syndrome = calculate_ecc(cap_high, cap_low) ^ cap_ecc; | ||
821 | |||
822 | /* Check if a data line is stuck... */ | ||
823 | for (i = 0; i < 64; i++) { | ||
824 | if (syndrome == syndrome_from_bit(i)) { | ||
825 | *bad_data_bit = i; | ||
826 | return; | ||
827 | } | ||
828 | } | ||
829 | |||
830 | /* If data is correct, check ECC bits for errors... */ | ||
831 | for (i = 0; i < 8; i++) { | ||
832 | if ((syndrome >> i) & 0x1) { | ||
833 | *bad_ecc_bit = i; | ||
834 | return; | ||
835 | } | ||
836 | } | ||
837 | } | ||
838 | |||
839 | #define make64(high, low) (((u64)(high) << 32) | (low)) | ||
840 | |||
841 | static void mpc85xx_mc_check(struct mem_ctl_info *mci) | ||
842 | { | ||
843 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
844 | struct csrow_info *csrow; | ||
845 | u32 bus_width; | ||
846 | u32 err_detect; | ||
847 | u32 syndrome; | ||
848 | u64 err_addr; | ||
849 | u32 pfn; | ||
850 | int row_index; | ||
851 | u32 cap_high; | ||
852 | u32 cap_low; | ||
853 | int bad_data_bit; | ||
854 | int bad_ecc_bit; | ||
855 | |||
856 | err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT); | ||
857 | if (!err_detect) | ||
858 | return; | ||
859 | |||
860 | mpc85xx_mc_printk(mci, KERN_ERR, "Err Detect Register: %#8.8x\n", | ||
861 | err_detect); | ||
862 | |||
863 | /* no more processing if not ECC bit errors */ | ||
864 | if (!(err_detect & (DDR_EDE_SBE | DDR_EDE_MBE))) { | ||
865 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect); | ||
866 | return; | ||
867 | } | ||
868 | |||
869 | syndrome = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ECC); | ||
870 | |||
871 | /* Mask off appropriate bits of syndrome based on bus width */ | ||
872 | bus_width = (in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG) & | ||
873 | DSC_DBW_MASK) ? 32 : 64; | ||
874 | if (bus_width == 64) | ||
875 | syndrome &= 0xff; | ||
876 | else | ||
877 | syndrome &= 0xffff; | ||
878 | |||
879 | err_addr = make64( | ||
880 | in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_EXT_ADDRESS), | ||
881 | in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ADDRESS)); | ||
882 | pfn = err_addr >> PAGE_SHIFT; | ||
883 | |||
884 | for (row_index = 0; row_index < mci->nr_csrows; row_index++) { | ||
885 | csrow = mci->csrows[row_index]; | ||
886 | if ((pfn >= csrow->first_page) && (pfn <= csrow->last_page)) | ||
887 | break; | ||
888 | } | ||
889 | |||
890 | cap_high = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_DATA_HI); | ||
891 | cap_low = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_DATA_LO); | ||
892 | |||
893 | /* | ||
894 | * Analyze single-bit errors on 64-bit wide buses | ||
895 | * TODO: Add support for 32-bit wide buses | ||
896 | */ | ||
897 | if ((err_detect & DDR_EDE_SBE) && (bus_width == 64)) { | ||
898 | sbe_ecc_decode(cap_high, cap_low, syndrome, | ||
899 | &bad_data_bit, &bad_ecc_bit); | ||
900 | |||
901 | if (bad_data_bit != -1) | ||
902 | mpc85xx_mc_printk(mci, KERN_ERR, | ||
903 | "Faulty Data bit: %d\n", bad_data_bit); | ||
904 | if (bad_ecc_bit != -1) | ||
905 | mpc85xx_mc_printk(mci, KERN_ERR, | ||
906 | "Faulty ECC bit: %d\n", bad_ecc_bit); | ||
907 | |||
908 | mpc85xx_mc_printk(mci, KERN_ERR, | ||
909 | "Expected Data / ECC:\t%#8.8x_%08x / %#2.2x\n", | ||
910 | cap_high ^ (1 << (bad_data_bit - 32)), | ||
911 | cap_low ^ (1 << bad_data_bit), | ||
912 | syndrome ^ (1 << bad_ecc_bit)); | ||
913 | } | ||
914 | |||
915 | mpc85xx_mc_printk(mci, KERN_ERR, | ||
916 | "Captured Data / ECC:\t%#8.8x_%08x / %#2.2x\n", | ||
917 | cap_high, cap_low, syndrome); | ||
918 | mpc85xx_mc_printk(mci, KERN_ERR, "Err addr: %#8.8llx\n", err_addr); | ||
919 | mpc85xx_mc_printk(mci, KERN_ERR, "PFN: %#8.8x\n", pfn); | ||
920 | |||
921 | /* we are out of range */ | ||
922 | if (row_index == mci->nr_csrows) | ||
923 | mpc85xx_mc_printk(mci, KERN_ERR, "PFN out of range!\n"); | ||
924 | |||
925 | if (err_detect & DDR_EDE_SBE) | ||
926 | edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, | ||
927 | pfn, err_addr & ~PAGE_MASK, syndrome, | ||
928 | row_index, 0, -1, | ||
929 | mci->ctl_name, ""); | ||
930 | |||
931 | if (err_detect & DDR_EDE_MBE) | ||
932 | edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, | ||
933 | pfn, err_addr & ~PAGE_MASK, syndrome, | ||
934 | row_index, 0, -1, | ||
935 | mci->ctl_name, ""); | ||
936 | |||
937 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect); | ||
938 | } | ||
939 | |||
940 | static irqreturn_t mpc85xx_mc_isr(int irq, void *dev_id) | ||
941 | { | ||
942 | struct mem_ctl_info *mci = dev_id; | ||
943 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
944 | u32 err_detect; | ||
945 | |||
946 | err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT); | ||
947 | if (!err_detect) | ||
948 | return IRQ_NONE; | ||
949 | |||
950 | mpc85xx_mc_check(mci); | ||
951 | |||
952 | return IRQ_HANDLED; | ||
953 | } | ||
954 | |||
955 | static void mpc85xx_init_csrows(struct mem_ctl_info *mci) | ||
956 | { | ||
957 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
958 | struct csrow_info *csrow; | ||
959 | struct dimm_info *dimm; | ||
960 | u32 sdram_ctl; | ||
961 | u32 sdtype; | ||
962 | enum mem_type mtype; | ||
963 | u32 cs_bnds; | ||
964 | int index; | ||
965 | |||
966 | sdram_ctl = in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG); | ||
967 | |||
968 | sdtype = sdram_ctl & DSC_SDTYPE_MASK; | ||
969 | if (sdram_ctl & DSC_RD_EN) { | ||
970 | switch (sdtype) { | ||
971 | case DSC_SDTYPE_DDR: | ||
972 | mtype = MEM_RDDR; | ||
973 | break; | ||
974 | case DSC_SDTYPE_DDR2: | ||
975 | mtype = MEM_RDDR2; | ||
976 | break; | ||
977 | case DSC_SDTYPE_DDR3: | ||
978 | mtype = MEM_RDDR3; | ||
979 | break; | ||
980 | default: | ||
981 | mtype = MEM_UNKNOWN; | ||
982 | break; | ||
983 | } | ||
984 | } else { | ||
985 | switch (sdtype) { | ||
986 | case DSC_SDTYPE_DDR: | ||
987 | mtype = MEM_DDR; | ||
988 | break; | ||
989 | case DSC_SDTYPE_DDR2: | ||
990 | mtype = MEM_DDR2; | ||
991 | break; | ||
992 | case DSC_SDTYPE_DDR3: | ||
993 | mtype = MEM_DDR3; | ||
994 | break; | ||
995 | default: | ||
996 | mtype = MEM_UNKNOWN; | ||
997 | break; | ||
998 | } | ||
999 | } | ||
1000 | |||
1001 | for (index = 0; index < mci->nr_csrows; index++) { | ||
1002 | u32 start; | ||
1003 | u32 end; | ||
1004 | |||
1005 | csrow = mci->csrows[index]; | ||
1006 | dimm = csrow->channels[0]->dimm; | ||
1007 | |||
1008 | cs_bnds = in_be32(pdata->mc_vbase + MPC85XX_MC_CS_BNDS_0 + | ||
1009 | (index * MPC85XX_MC_CS_BNDS_OFS)); | ||
1010 | |||
1011 | start = (cs_bnds & 0xffff0000) >> 16; | ||
1012 | end = (cs_bnds & 0x0000ffff); | ||
1013 | |||
1014 | if (start == end) | ||
1015 | continue; /* not populated */ | ||
1016 | |||
1017 | start <<= (24 - PAGE_SHIFT); | ||
1018 | end <<= (24 - PAGE_SHIFT); | ||
1019 | end |= (1 << (24 - PAGE_SHIFT)) - 1; | ||
1020 | |||
1021 | csrow->first_page = start; | ||
1022 | csrow->last_page = end; | ||
1023 | |||
1024 | dimm->nr_pages = end + 1 - start; | ||
1025 | dimm->grain = 8; | ||
1026 | dimm->mtype = mtype; | ||
1027 | dimm->dtype = DEV_UNKNOWN; | ||
1028 | if (sdram_ctl & DSC_X32_EN) | ||
1029 | dimm->dtype = DEV_X32; | ||
1030 | dimm->edac_mode = EDAC_SECDED; | ||
1031 | } | ||
1032 | } | ||
1033 | |||
1034 | static int mpc85xx_mc_err_probe(struct platform_device *op) | ||
1035 | { | ||
1036 | struct mem_ctl_info *mci; | ||
1037 | struct edac_mc_layer layers[2]; | ||
1038 | struct mpc85xx_mc_pdata *pdata; | ||
1039 | struct resource r; | ||
1040 | u32 sdram_ctl; | ||
1041 | int res; | ||
1042 | |||
1043 | if (!devres_open_group(&op->dev, mpc85xx_mc_err_probe, GFP_KERNEL)) | ||
1044 | return -ENOMEM; | ||
1045 | |||
1046 | layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; | ||
1047 | layers[0].size = 4; | ||
1048 | layers[0].is_virt_csrow = true; | ||
1049 | layers[1].type = EDAC_MC_LAYER_CHANNEL; | ||
1050 | layers[1].size = 1; | ||
1051 | layers[1].is_virt_csrow = false; | ||
1052 | mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), layers, | ||
1053 | sizeof(*pdata)); | ||
1054 | if (!mci) { | ||
1055 | devres_release_group(&op->dev, mpc85xx_mc_err_probe); | ||
1056 | return -ENOMEM; | ||
1057 | } | ||
1058 | |||
1059 | pdata = mci->pvt_info; | ||
1060 | pdata->name = "mpc85xx_mc_err"; | ||
1061 | pdata->irq = NO_IRQ; | ||
1062 | mci->pdev = &op->dev; | ||
1063 | pdata->edac_idx = edac_mc_idx++; | ||
1064 | dev_set_drvdata(mci->pdev, mci); | ||
1065 | mci->ctl_name = pdata->name; | ||
1066 | mci->dev_name = pdata->name; | ||
1067 | |||
1068 | res = of_address_to_resource(op->dev.of_node, 0, &r); | ||
1069 | if (res) { | ||
1070 | printk(KERN_ERR "%s: Unable to get resource for MC err regs\n", | ||
1071 | __func__); | ||
1072 | goto err; | ||
1073 | } | ||
1074 | |||
1075 | if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r), | ||
1076 | pdata->name)) { | ||
1077 | printk(KERN_ERR "%s: Error while requesting mem region\n", | ||
1078 | __func__); | ||
1079 | res = -EBUSY; | ||
1080 | goto err; | ||
1081 | } | ||
1082 | |||
1083 | pdata->mc_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r)); | ||
1084 | if (!pdata->mc_vbase) { | ||
1085 | printk(KERN_ERR "%s: Unable to setup MC err regs\n", __func__); | ||
1086 | res = -ENOMEM; | ||
1087 | goto err; | ||
1088 | } | ||
1089 | |||
1090 | sdram_ctl = in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG); | ||
1091 | if (!(sdram_ctl & DSC_ECC_EN)) { | ||
1092 | /* no ECC */ | ||
1093 | printk(KERN_WARNING "%s: No ECC DIMMs discovered\n", __func__); | ||
1094 | res = -ENODEV; | ||
1095 | goto err; | ||
1096 | } | ||
1097 | |||
1098 | edac_dbg(3, "init mci\n"); | ||
1099 | mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_RDDR2 | | ||
1100 | MEM_FLAG_DDR | MEM_FLAG_DDR2; | ||
1101 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; | ||
1102 | mci->edac_cap = EDAC_FLAG_SECDED; | ||
1103 | mci->mod_name = EDAC_MOD_STR; | ||
1104 | mci->mod_ver = MPC85XX_REVISION; | ||
1105 | |||
1106 | if (edac_op_state == EDAC_OPSTATE_POLL) | ||
1107 | mci->edac_check = mpc85xx_mc_check; | ||
1108 | |||
1109 | mci->ctl_page_to_phys = NULL; | ||
1110 | |||
1111 | mci->scrub_mode = SCRUB_SW_SRC; | ||
1112 | |||
1113 | mpc85xx_init_csrows(mci); | ||
1114 | |||
1115 | /* store the original error disable bits */ | ||
1116 | orig_ddr_err_disable = | ||
1117 | in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE); | ||
1118 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE, 0); | ||
1119 | |||
1120 | /* clear all error bits */ | ||
1121 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, ~0); | ||
1122 | |||
1123 | if (edac_mc_add_mc_with_groups(mci, mpc85xx_dev_groups)) { | ||
1124 | edac_dbg(3, "failed edac_mc_add_mc()\n"); | ||
1125 | goto err; | ||
1126 | } | ||
1127 | |||
1128 | if (edac_op_state == EDAC_OPSTATE_INT) { | ||
1129 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_INT_EN, | ||
1130 | DDR_EIE_MBEE | DDR_EIE_SBEE); | ||
1131 | |||
1132 | /* store the original error management threshold */ | ||
1133 | orig_ddr_err_sbe = in_be32(pdata->mc_vbase + | ||
1134 | MPC85XX_MC_ERR_SBE) & 0xff0000; | ||
1135 | |||
1136 | /* set threshold to 1 error per interrupt */ | ||
1137 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, 0x10000); | ||
1138 | |||
1139 | /* register interrupts */ | ||
1140 | pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); | ||
1141 | res = devm_request_irq(&op->dev, pdata->irq, | ||
1142 | mpc85xx_mc_isr, | ||
1143 | IRQF_SHARED, | ||
1144 | "[EDAC] MC err", mci); | ||
1145 | if (res < 0) { | ||
1146 | printk(KERN_ERR "%s: Unable to request irq %d for " | ||
1147 | "MPC85xx DRAM ERR\n", __func__, pdata->irq); | ||
1148 | irq_dispose_mapping(pdata->irq); | ||
1149 | res = -ENODEV; | ||
1150 | goto err2; | ||
1151 | } | ||
1152 | |||
1153 | printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for MC\n", | ||
1154 | pdata->irq); | ||
1155 | } | ||
1156 | |||
1157 | devres_remove_group(&op->dev, mpc85xx_mc_err_probe); | ||
1158 | edac_dbg(3, "success\n"); | ||
1159 | printk(KERN_INFO EDAC_MOD_STR " MC err registered\n"); | ||
1160 | |||
1161 | return 0; | ||
1162 | |||
1163 | err2: | ||
1164 | edac_mc_del_mc(&op->dev); | ||
1165 | err: | ||
1166 | devres_release_group(&op->dev, mpc85xx_mc_err_probe); | ||
1167 | edac_mc_free(mci); | ||
1168 | return res; | ||
1169 | } | ||
1170 | |||
1171 | static int mpc85xx_mc_err_remove(struct platform_device *op) | ||
1172 | { | ||
1173 | struct mem_ctl_info *mci = dev_get_drvdata(&op->dev); | ||
1174 | struct mpc85xx_mc_pdata *pdata = mci->pvt_info; | ||
1175 | |||
1176 | edac_dbg(0, "\n"); | ||
1177 | |||
1178 | if (edac_op_state == EDAC_OPSTATE_INT) { | ||
1179 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_INT_EN, 0); | ||
1180 | irq_dispose_mapping(pdata->irq); | ||
1181 | } | ||
1182 | |||
1183 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE, | ||
1184 | orig_ddr_err_disable); | ||
1185 | out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, orig_ddr_err_sbe); | ||
1186 | |||
1187 | edac_mc_del_mc(&op->dev); | ||
1188 | edac_mc_free(mci); | ||
1189 | return 0; | ||
1190 | } | ||
1191 | |||
1192 | static const struct of_device_id mpc85xx_mc_err_of_match[] = { | 629 | static const struct of_device_id mpc85xx_mc_err_of_match[] = { |
1193 | /* deprecate the fsl,85.. forms in the future, 2.6.30? */ | 630 | /* deprecate the fsl,85.. forms in the future, 2.6.30? */ |
1194 | { .compatible = "fsl,8540-memory-controller", }, | 631 | { .compatible = "fsl,8540-memory-controller", }, |
@@ -1217,22 +654,14 @@ static const struct of_device_id mpc85xx_mc_err_of_match[] = { | |||
1217 | MODULE_DEVICE_TABLE(of, mpc85xx_mc_err_of_match); | 654 | MODULE_DEVICE_TABLE(of, mpc85xx_mc_err_of_match); |
1218 | 655 | ||
1219 | static struct platform_driver mpc85xx_mc_err_driver = { | 656 | static struct platform_driver mpc85xx_mc_err_driver = { |
1220 | .probe = mpc85xx_mc_err_probe, | 657 | .probe = fsl_mc_err_probe, |
1221 | .remove = mpc85xx_mc_err_remove, | 658 | .remove = fsl_mc_err_remove, |
1222 | .driver = { | 659 | .driver = { |
1223 | .name = "mpc85xx_mc_err", | 660 | .name = "mpc85xx_mc_err", |
1224 | .of_match_table = mpc85xx_mc_err_of_match, | 661 | .of_match_table = mpc85xx_mc_err_of_match, |
1225 | }, | 662 | }, |
1226 | }; | 663 | }; |
1227 | 664 | ||
1228 | #ifdef CONFIG_FSL_SOC_BOOKE | ||
1229 | static void __init mpc85xx_mc_clear_rfxe(void *data) | ||
1230 | { | ||
1231 | orig_hid1[smp_processor_id()] = mfspr(SPRN_HID1); | ||
1232 | mtspr(SPRN_HID1, (orig_hid1[smp_processor_id()] & ~HID1_RFXE)); | ||
1233 | } | ||
1234 | #endif | ||
1235 | |||
1236 | static struct platform_driver * const drivers[] = { | 665 | static struct platform_driver * const drivers[] = { |
1237 | &mpc85xx_mc_err_driver, | 666 | &mpc85xx_mc_err_driver, |
1238 | &mpc85xx_l2_err_driver, | 667 | &mpc85xx_l2_err_driver, |
@@ -1246,8 +675,7 @@ static int __init mpc85xx_mc_init(void) | |||
1246 | int res = 0; | 675 | int res = 0; |
1247 | u32 __maybe_unused pvr = 0; | 676 | u32 __maybe_unused pvr = 0; |
1248 | 677 | ||
1249 | printk(KERN_INFO "Freescale(R) MPC85xx EDAC driver, " | 678 | pr_info("Freescale(R) MPC85xx EDAC driver, (C) 2006 Montavista Software\n"); |
1250 | "(C) 2006 Montavista Software\n"); | ||
1251 | 679 | ||
1252 | /* make sure error reporting method is sane */ | 680 | /* make sure error reporting method is sane */ |
1253 | switch (edac_op_state) { | 681 | switch (edac_op_state) { |
@@ -1261,44 +689,15 @@ static int __init mpc85xx_mc_init(void) | |||
1261 | 689 | ||
1262 | res = platform_register_drivers(drivers, ARRAY_SIZE(drivers)); | 690 | res = platform_register_drivers(drivers, ARRAY_SIZE(drivers)); |
1263 | if (res) | 691 | if (res) |
1264 | printk(KERN_WARNING EDAC_MOD_STR "drivers fail to register\n"); | 692 | pr_warn(EDAC_MOD_STR "drivers fail to register\n"); |
1265 | |||
1266 | #ifdef CONFIG_FSL_SOC_BOOKE | ||
1267 | pvr = mfspr(SPRN_PVR); | ||
1268 | |||
1269 | if ((PVR_VER(pvr) == PVR_VER_E500V1) || | ||
1270 | (PVR_VER(pvr) == PVR_VER_E500V2)) { | ||
1271 | /* | ||
1272 | * need to clear HID1[RFXE] to disable machine check int | ||
1273 | * so we can catch it | ||
1274 | */ | ||
1275 | if (edac_op_state == EDAC_OPSTATE_INT) | ||
1276 | on_each_cpu(mpc85xx_mc_clear_rfxe, NULL, 0); | ||
1277 | } | ||
1278 | #endif | ||
1279 | 693 | ||
1280 | return 0; | 694 | return 0; |
1281 | } | 695 | } |
1282 | 696 | ||
1283 | module_init(mpc85xx_mc_init); | 697 | module_init(mpc85xx_mc_init); |
1284 | 698 | ||
1285 | #ifdef CONFIG_FSL_SOC_BOOKE | ||
1286 | static void __exit mpc85xx_mc_restore_hid1(void *data) | ||
1287 | { | ||
1288 | mtspr(SPRN_HID1, orig_hid1[smp_processor_id()]); | ||
1289 | } | ||
1290 | #endif | ||
1291 | |||
1292 | static void __exit mpc85xx_mc_exit(void) | 699 | static void __exit mpc85xx_mc_exit(void) |
1293 | { | 700 | { |
1294 | #ifdef CONFIG_FSL_SOC_BOOKE | ||
1295 | u32 pvr = mfspr(SPRN_PVR); | ||
1296 | |||
1297 | if ((PVR_VER(pvr) == PVR_VER_E500V1) || | ||
1298 | (PVR_VER(pvr) == PVR_VER_E500V2)) { | ||
1299 | on_each_cpu(mpc85xx_mc_restore_hid1, NULL, 0); | ||
1300 | } | ||
1301 | #endif | ||
1302 | platform_unregister_drivers(drivers, ARRAY_SIZE(drivers)); | 701 | platform_unregister_drivers(drivers, ARRAY_SIZE(drivers)); |
1303 | } | 702 | } |
1304 | 703 | ||
diff --git a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h index 9352e88d53e5..3f6fb16ad34f 100644 --- a/drivers/edac/mpc85xx_edac.h +++ b/drivers/edac/mpc85xx_edac.h | |||
@@ -17,65 +17,6 @@ | |||
17 | #define mpc85xx_printk(level, fmt, arg...) \ | 17 | #define mpc85xx_printk(level, fmt, arg...) \ |
18 | edac_printk(level, "MPC85xx", fmt, ##arg) | 18 | edac_printk(level, "MPC85xx", fmt, ##arg) |
19 | 19 | ||
20 | #define mpc85xx_mc_printk(mci, level, fmt, arg...) \ | ||
21 | edac_mc_chipset_printk(mci, level, "MPC85xx", fmt, ##arg) | ||
22 | |||
23 | /* | ||
24 | * DRAM error defines | ||
25 | */ | ||
26 | |||
27 | /* DDR_SDRAM_CFG */ | ||
28 | #define MPC85XX_MC_DDR_SDRAM_CFG 0x0110 | ||
29 | #define MPC85XX_MC_CS_BNDS_0 0x0000 | ||
30 | #define MPC85XX_MC_CS_BNDS_1 0x0008 | ||
31 | #define MPC85XX_MC_CS_BNDS_2 0x0010 | ||
32 | #define MPC85XX_MC_CS_BNDS_3 0x0018 | ||
33 | #define MPC85XX_MC_CS_BNDS_OFS 0x0008 | ||
34 | |||
35 | #define MPC85XX_MC_DATA_ERR_INJECT_HI 0x0e00 | ||
36 | #define MPC85XX_MC_DATA_ERR_INJECT_LO 0x0e04 | ||
37 | #define MPC85XX_MC_ECC_ERR_INJECT 0x0e08 | ||
38 | #define MPC85XX_MC_CAPTURE_DATA_HI 0x0e20 | ||
39 | #define MPC85XX_MC_CAPTURE_DATA_LO 0x0e24 | ||
40 | #define MPC85XX_MC_CAPTURE_ECC 0x0e28 | ||
41 | #define MPC85XX_MC_ERR_DETECT 0x0e40 | ||
42 | #define MPC85XX_MC_ERR_DISABLE 0x0e44 | ||
43 | #define MPC85XX_MC_ERR_INT_EN 0x0e48 | ||
44 | #define MPC85XX_MC_CAPTURE_ATRIBUTES 0x0e4c | ||
45 | #define MPC85XX_MC_CAPTURE_ADDRESS 0x0e50 | ||
46 | #define MPC85XX_MC_CAPTURE_EXT_ADDRESS 0x0e54 | ||
47 | #define MPC85XX_MC_ERR_SBE 0x0e58 | ||
48 | |||
49 | #define DSC_MEM_EN 0x80000000 | ||
50 | #define DSC_ECC_EN 0x20000000 | ||
51 | #define DSC_RD_EN 0x10000000 | ||
52 | #define DSC_DBW_MASK 0x00180000 | ||
53 | #define DSC_DBW_32 0x00080000 | ||
54 | #define DSC_DBW_64 0x00000000 | ||
55 | |||
56 | #define DSC_SDTYPE_MASK 0x07000000 | ||
57 | |||
58 | #define DSC_SDTYPE_DDR 0x02000000 | ||
59 | #define DSC_SDTYPE_DDR2 0x03000000 | ||
60 | #define DSC_SDTYPE_DDR3 0x07000000 | ||
61 | #define DSC_X32_EN 0x00000020 | ||
62 | |||
63 | /* Err_Int_En */ | ||
64 | #define DDR_EIE_MSEE 0x1 /* memory select */ | ||
65 | #define DDR_EIE_SBEE 0x4 /* single-bit ECC error */ | ||
66 | #define DDR_EIE_MBEE 0x8 /* multi-bit ECC error */ | ||
67 | |||
68 | /* Err_Detect */ | ||
69 | #define DDR_EDE_MSE 0x1 /* memory select */ | ||
70 | #define DDR_EDE_SBE 0x4 /* single-bit ECC error */ | ||
71 | #define DDR_EDE_MBE 0x8 /* multi-bit ECC error */ | ||
72 | #define DDR_EDE_MME 0x80000000 /* multiple memory errors */ | ||
73 | |||
74 | /* Err_Disable */ | ||
75 | #define DDR_EDI_MSED 0x1 /* memory select disable */ | ||
76 | #define DDR_EDI_SBED 0x4 /* single-bit ECC error disable */ | ||
77 | #define DDR_EDI_MBED 0x8 /* multi-bit ECC error disable */ | ||
78 | |||
79 | /* | 20 | /* |
80 | * L2 Err defines | 21 | * L2 Err defines |
81 | */ | 22 | */ |
@@ -149,13 +90,6 @@ | |||
149 | #define MPC85XX_PCIE_ERR_CAP_R2 0x0030 | 90 | #define MPC85XX_PCIE_ERR_CAP_R2 0x0030 |
150 | #define MPC85XX_PCIE_ERR_CAP_R3 0x0034 | 91 | #define MPC85XX_PCIE_ERR_CAP_R3 0x0034 |
151 | 92 | ||
152 | struct mpc85xx_mc_pdata { | ||
153 | char *name; | ||
154 | int edac_idx; | ||
155 | void __iomem *mc_vbase; | ||
156 | int irq; | ||
157 | }; | ||
158 | |||
159 | struct mpc85xx_l2_pdata { | 93 | struct mpc85xx_l2_pdata { |
160 | char *name; | 94 | char *name; |
161 | int edac_idx; | 95 | int edac_idx; |
diff --git a/drivers/edac/mv64x60_edac.c b/drivers/edac/mv64x60_edac.c index 6c54127e6eae..cb9b8577acbc 100644 --- a/drivers/edac/mv64x60_edac.c +++ b/drivers/edac/mv64x60_edac.c | |||
@@ -118,7 +118,6 @@ static int mv64x60_pci_err_probe(struct platform_device *pdev) | |||
118 | 118 | ||
119 | pdata->pci_hose = pdev->id; | 119 | pdata->pci_hose = pdev->id; |
120 | pdata->name = "mpc85xx_pci_err"; | 120 | pdata->name = "mpc85xx_pci_err"; |
121 | pdata->irq = NO_IRQ; | ||
122 | platform_set_drvdata(pdev, pci); | 121 | platform_set_drvdata(pdev, pci); |
123 | pci->dev = &pdev->dev; | 122 | pci->dev = &pdev->dev; |
124 | pci->dev_name = dev_name(&pdev->dev); | 123 | pci->dev_name = dev_name(&pdev->dev); |
@@ -291,7 +290,6 @@ static int mv64x60_sram_err_probe(struct platform_device *pdev) | |||
291 | 290 | ||
292 | pdata = edac_dev->pvt_info; | 291 | pdata = edac_dev->pvt_info; |
293 | pdata->name = "mv64x60_sram_err"; | 292 | pdata->name = "mv64x60_sram_err"; |
294 | pdata->irq = NO_IRQ; | ||
295 | edac_dev->dev = &pdev->dev; | 293 | edac_dev->dev = &pdev->dev; |
296 | platform_set_drvdata(pdev, edac_dev); | 294 | platform_set_drvdata(pdev, edac_dev); |
297 | edac_dev->dev_name = dev_name(&pdev->dev); | 295 | edac_dev->dev_name = dev_name(&pdev->dev); |
@@ -459,7 +457,6 @@ static int mv64x60_cpu_err_probe(struct platform_device *pdev) | |||
459 | 457 | ||
460 | pdata = edac_dev->pvt_info; | 458 | pdata = edac_dev->pvt_info; |
461 | pdata->name = "mv64x60_cpu_err"; | 459 | pdata->name = "mv64x60_cpu_err"; |
462 | pdata->irq = NO_IRQ; | ||
463 | edac_dev->dev = &pdev->dev; | 460 | edac_dev->dev = &pdev->dev; |
464 | platform_set_drvdata(pdev, edac_dev); | 461 | platform_set_drvdata(pdev, edac_dev); |
465 | edac_dev->dev_name = dev_name(&pdev->dev); | 462 | edac_dev->dev_name = dev_name(&pdev->dev); |
@@ -727,7 +724,6 @@ static int mv64x60_mc_err_probe(struct platform_device *pdev) | |||
727 | mci->pdev = &pdev->dev; | 724 | mci->pdev = &pdev->dev; |
728 | platform_set_drvdata(pdev, mci); | 725 | platform_set_drvdata(pdev, mci); |
729 | pdata->name = "mv64x60_mc_err"; | 726 | pdata->name = "mv64x60_mc_err"; |
730 | pdata->irq = NO_IRQ; | ||
731 | mci->dev_name = dev_name(&pdev->dev); | 727 | mci->dev_name = dev_name(&pdev->dev); |
732 | pdata->edac_idx = edac_mc_idx++; | 728 | pdata->edac_idx = edac_mc_idx++; |
733 | 729 | ||
diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c index d3a64ba61fa3..691ce25e9010 100644 --- a/drivers/edac/ppc4xx_edac.c +++ b/drivers/edac/ppc4xx_edac.c | |||
@@ -1029,8 +1029,6 @@ static int ppc4xx_edac_mc_init(struct mem_ctl_info *mci, | |||
1029 | pdata = mci->pvt_info; | 1029 | pdata = mci->pvt_info; |
1030 | 1030 | ||
1031 | pdata->dcr_host = *dcr_host; | 1031 | pdata->dcr_host = *dcr_host; |
1032 | pdata->irqs.sec = NO_IRQ; | ||
1033 | pdata->irqs.ded = NO_IRQ; | ||
1034 | 1032 | ||
1035 | /* Initialize controller capabilities and configuration */ | 1033 | /* Initialize controller capabilities and configuration */ |
1036 | 1034 | ||
@@ -1111,7 +1109,7 @@ static int ppc4xx_edac_register_irq(struct platform_device *op, | |||
1111 | ded_irq = irq_of_parse_and_map(np, INTMAP_ECCDED_INDEX); | 1109 | ded_irq = irq_of_parse_and_map(np, INTMAP_ECCDED_INDEX); |
1112 | sec_irq = irq_of_parse_and_map(np, INTMAP_ECCSEC_INDEX); | 1110 | sec_irq = irq_of_parse_and_map(np, INTMAP_ECCSEC_INDEX); |
1113 | 1111 | ||
1114 | if (ded_irq == NO_IRQ || sec_irq == NO_IRQ) { | 1112 | if (!ded_irq || !sec_irq) { |
1115 | ppc4xx_edac_mc_printk(KERN_ERR, mci, | 1113 | ppc4xx_edac_mc_printk(KERN_ERR, mci, |
1116 | "Unable to map interrupts.\n"); | 1114 | "Unable to map interrupts.\n"); |
1117 | status = -ENODEV; | 1115 | status = -ENODEV; |
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index ce0067b7a2f6..54775221a01f 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c | |||
@@ -2474,7 +2474,7 @@ static int sbridge_mci_bind_devs(struct mem_ctl_info *mci, | |||
2474 | 2474 | ||
2475 | /* Check if everything were registered */ | 2475 | /* Check if everything were registered */ |
2476 | if (!pvt->pci_sad0 || !pvt->pci_sad1 || !pvt->pci_ha0 || | 2476 | if (!pvt->pci_sad0 || !pvt->pci_sad1 || !pvt->pci_ha0 || |
2477 | !pvt-> pci_tad || !pvt->pci_ras || !pvt->pci_ta) | 2477 | !pvt->pci_ras || !pvt->pci_ta) |
2478 | goto enodev; | 2478 | goto enodev; |
2479 | 2479 | ||
2480 | if (saw_chan_mask != 0x0f) | 2480 | if (saw_chan_mask != 0x0f) |
@@ -2563,8 +2563,7 @@ static int ibridge_mci_bind_devs(struct mem_ctl_info *mci, | |||
2563 | 2563 | ||
2564 | /* Check if everything were registered */ | 2564 | /* Check if everything were registered */ |
2565 | if (!pvt->pci_sad0 || !pvt->pci_ha0 || !pvt->pci_br0 || | 2565 | if (!pvt->pci_sad0 || !pvt->pci_ha0 || !pvt->pci_br0 || |
2566 | !pvt->pci_br1 || !pvt->pci_tad || !pvt->pci_ras || | 2566 | !pvt->pci_br1 || !pvt->pci_ras || !pvt->pci_ta) |
2567 | !pvt->pci_ta) | ||
2568 | goto enodev; | 2567 | goto enodev; |
2569 | 2568 | ||
2570 | if (saw_chan_mask != 0x0f && /* -EN */ | 2569 | if (saw_chan_mask != 0x0f && /* -EN */ |
diff --git a/drivers/edac/wq.c b/drivers/edac/wq.c index 1b8c07e44fd8..2a9a11ae2461 100644 --- a/drivers/edac/wq.c +++ b/drivers/edac/wq.c | |||
@@ -27,7 +27,7 @@ EXPORT_SYMBOL_GPL(edac_stop_work); | |||
27 | 27 | ||
28 | int edac_workqueue_setup(void) | 28 | int edac_workqueue_setup(void) |
29 | { | 29 | { |
30 | wq = create_singlethread_workqueue("edac-poller"); | 30 | wq = alloc_ordered_workqueue("edac-poller", WQ_MEM_RECLAIM); |
31 | if (!wq) | 31 | if (!wq) |
32 | return -ENODEV; | 32 | return -ENODEV; |
33 | else | 33 | else |