From 9dd344aed7f1855ca23db12653c900bd697f742c Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Thu, 14 Jul 2016 11:06:39 -0500 Subject: Documentation: dt: socfpga: Add Arria10 NAND EDAC binding Add the device tree bindings needed to support the Altera NAND FIFO buffers on the Arria10 chip. Signed-off-by: Thor Thayer Acked-by: Rob Herring Cc: devicetree@vger.kernel.org Cc: dinguyen@opensource.altera.com Cc: linux-arm-kernel@lists.infradead.org Cc: linux-edac Link: http://lkml.kernel.org/r/1468512408-5156-2-git-send-email-tthayer@opensource.altera.com Signed-off-by: Borislav Petkov --- .../bindings/arm/altera/socfpga-eccmgr.txt | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt b/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt index b545856a444f..1bcbab216294 100644 --- a/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt +++ b/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt @@ -90,6 +90,14 @@ Required Properties: - interrupts : Should be single bit error interrupt, then double bit error interrupt, in this order. +NAND FIFO ECC +Required Properties: +- compatible : Should be "altr,socfpga-nand-ecc" +- reg : Address and size for ECC block registers. +- altr,ecc-parent : phandle to parent NAND node. +- interrupts : Should be single bit error interrupt, then double bit error + interrupt, in this order. + Example: eccmgr: eccmgr@ffd06000 { @@ -132,4 +140,28 @@ Example: interrupts = <5 IRQ_TYPE_LEVEL_HIGH>, <37 IRQ_TYPE_LEVEL_HIGH>; }; + + nand-buf-ecc@ff8c2000 { + compatible = "altr,socfpga-nand-ecc"; + reg = <0xff8c2000 0x400>; + altr,ecc-parent = <&nand>; + interrupts = <11 IRQ_TYPE_LEVEL_HIGH>, + <43 IRQ_TYPE_LEVEL_HIGH>; + }; + + nand-rd-ecc@ff8c2400 { + compatible = "altr,socfpga-nand-ecc"; + reg = <0xff8c2400 0x400>; + altr,ecc-parent = <&nand>; + interrupts = <13 IRQ_TYPE_LEVEL_HIGH>, + <45 IRQ_TYPE_LEVEL_HIGH>; + }; + + nand-wr-ecc@ff8c2800 { + compatible = "altr,socfpga-nand-ecc"; + reg = <0xff8c2800 0x400>; + altr,ecc-parent = <&nand>; + interrupts = <12 IRQ_TYPE_LEVEL_HIGH>, + <44 IRQ_TYPE_LEVEL_HIGH>; + }; }; -- cgit v1.2.3 From e03934173a0a4c5a0fac51d1b5e5c01a94a8b64d Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Thu, 14 Jul 2016 11:06:40 -0500 Subject: Documentation: dt: socfpga: Add Arria10 DMA EDAC binding Add the device tree bindings needed to support the Altera DMA FIFO buffer on the Arria10 chip. Signed-off-by: Thor Thayer Acked-by: Rob Herring Cc: devicetree@vger.kernel.org Cc: dinguyen@opensource.altera.com Cc: linux-arm-kernel@lists.infradead.org Cc: linux-edac Link: http://lkml.kernel.org/r/1468512408-5156-3-git-send-email-tthayer@opensource.altera.com Signed-off-by: Borislav Petkov --- .../devicetree/bindings/arm/altera/socfpga-eccmgr.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt b/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt index 1bcbab216294..ad8245b8d568 100644 --- a/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt +++ b/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt @@ -98,6 +98,14 @@ Required Properties: - interrupts : Should be single bit error interrupt, then double bit error interrupt, in this order. +DMA FIFO ECC +Required Properties: +- compatible : Should be "altr,socfpga-dma-ecc" +- reg : Address and size for ECC block registers. +- altr,ecc-parent : phandle to parent DMA node. +- interrupts : Should be single bit error interrupt, then double bit error + interrupt, in this order. + Example: eccmgr: eccmgr@ffd06000 { @@ -164,4 +172,12 @@ Example: interrupts = <12 IRQ_TYPE_LEVEL_HIGH>, <44 IRQ_TYPE_LEVEL_HIGH>; }; + + dma-ecc@ff8c8000 { + compatible = "altr,socfpga-dma-ecc"; + reg = <0xff8c8000 0x400>; + altr,ecc-parent = <&pdma>; + interrupts = <10 IRQ_TYPE_LEVEL_HIGH>, + <42 IRQ_TYPE_LEVEL_HIGH>; + }; }; -- cgit v1.2.3 From 75e644c77d7c1d2b5414b5c8b043b7d56713f54d Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Thu, 14 Jul 2016 11:06:41 -0500 Subject: Documentation: dt: socfpga: Add Arria10 USB EDAC binding Add the device tree bindings needed to support the Altera USB FIFO buffer on the Arria10 chip. Signed-off-by: Thor Thayer Acked-by: Rob Herring Cc: devicetree@vger.kernel.org Cc: dinguyen@opensource.altera.com Cc: linux-arm-kernel@lists.infradead.org Cc: linux-edac Link: http://lkml.kernel.org/r/1468512408-5156-4-git-send-email-tthayer@opensource.altera.com Signed-off-by: Borislav Petkov --- .../devicetree/bindings/arm/altera/socfpga-eccmgr.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt b/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt index ad8245b8d568..3ffeb12374b7 100644 --- a/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt +++ b/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt @@ -106,6 +106,14 @@ Required Properties: - interrupts : Should be single bit error interrupt, then double bit error interrupt, in this order. +USB FIFO ECC +Required Properties: +- compatible : Should be "altr,socfpga-usb-ecc" +- reg : Address and size for ECC block registers. +- altr,ecc-parent : phandle to parent USB node. +- interrupts : Should be single bit error interrupt, then double bit error + interrupt, in this order. + Example: eccmgr: eccmgr@ffd06000 { @@ -179,5 +187,12 @@ Example: altr,ecc-parent = <&pdma>; interrupts = <10 IRQ_TYPE_LEVEL_HIGH>, <42 IRQ_TYPE_LEVEL_HIGH>; + + usb0-ecc@ff8c8800 { + compatible = "altr,socfpga-usb-ecc"; + reg = <0xff8c8800 0x400>; + altr,ecc-parent = <&usb0>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>, + <34 IRQ_TYPE_LEVEL_HIGH>; }; }; -- cgit v1.2.3 From d61d96f1c9b4276a8dd486be6678971037946990 Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Thu, 14 Jul 2016 11:06:42 -0500 Subject: Documentation: dt: socfpga: Add Arria10 QSPI EDAC binding Add the device tree bindings needed to support the Altera QSPI FIFO buffer on the Arria10 chip. Signed-off-by: Thor Thayer Acked-by: Rob Herring Cc: devicetree@vger.kernel.org Cc: dinguyen@opensource.altera.com Cc: linux-arm-kernel@lists.infradead.org Cc: linux-edac Link: http://lkml.kernel.org/r/1468512408-5156-5-git-send-email-tthayer@opensource.altera.com Signed-off-by: Borislav Petkov --- .../devicetree/bindings/arm/altera/socfpga-eccmgr.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt b/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt index 3ffeb12374b7..ee66df082a42 100644 --- a/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt +++ b/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt @@ -114,6 +114,14 @@ Required Properties: - interrupts : Should be single bit error interrupt, then double bit error interrupt, in this order. +QSPI FIFO ECC +Required Properties: +- compatible : Should be "altr,socfpga-qspi-ecc" +- reg : Address and size for ECC block registers. +- altr,ecc-parent : phandle to parent QSPI node. +- interrupts : Should be single bit error interrupt, then double bit error + interrupt, in this order. + Example: eccmgr: eccmgr@ffd06000 { @@ -195,4 +203,12 @@ Example: interrupts = <2 IRQ_TYPE_LEVEL_HIGH>, <34 IRQ_TYPE_LEVEL_HIGH>; }; + + qspi-ecc@ff8c8400 { + compatible = "altr,socfpga-qspi-ecc"; + reg = <0xff8c8400 0x400>; + altr,ecc-parent = <&qspi>; + interrupts = <14 IRQ_TYPE_LEVEL_HIGH>, + <46 IRQ_TYPE_LEVEL_HIGH>; + }; }; -- cgit v1.2.3 From c6882fb2e83525e97663df1d2d96f29d034189ab Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Thu, 14 Jul 2016 11:06:43 -0500 Subject: EDAC, altera: Add Arria10 NAND support Add Altera Arria10 NAND FIFO memory support. Signed-off-by: Thor Thayer Cc: dinguyen@opensource.altera.com Cc: linux-arm-kernel@lists.infradead.org Cc: linux-edac Link: http://lkml.kernel.org/r/1468512408-5156-6-git-send-email-tthayer@opensource.altera.com [ Reformat loop in altr_edac_a10_probe() for better readability. ] Signed-off-by: Borislav Petkov --- drivers/edac/Kconfig | 7 +++++++ drivers/edac/altera_edac.c | 46 ++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index d0c1dab9b435..47378b30c8c3 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -398,6 +398,13 @@ config EDAC_ALTERA_ETHERNET Support for error detection and correction on the Altera Ethernet FIFO Memory for Altera SoCs. +config EDAC_ALTERA_NAND + bool "Altera NAND FIFO ECC" + depends on EDAC_ALTERA=y && MTD_NAND_DENALI + help + Support for error detection and correction on the + Altera NAND FIFO Memory for Altera SoCs. + config EDAC_SYNOPSYS tristate "Synopsys DDR Memory Controller" depends on EDAC_MM_EDAC && ARCH_ZYNQ diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 2398d0701f5b..fe6374236bd9 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -1285,6 +1285,33 @@ early_initcall(socfpga_init_ethernet_ecc); #endif /* CONFIG_EDAC_ALTERA_ETHERNET */ +/********************** NAND Device Functions **********************/ + +#ifdef CONFIG_EDAC_ALTERA_NAND + +static const struct edac_device_prv_data a10_nandecc_data = { + .setup = altr_check_ecc_deps, + .ce_clear_mask = ALTR_A10_ECC_SERRPENA, + .ue_clear_mask = ALTR_A10_ECC_DERRPENA, + .dbgfs_name = "altr_trigger", + .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL, + .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, + .ce_set_mask = ALTR_A10_ECC_TSERRA, + .ue_set_mask = ALTR_A10_ECC_TDERRA, + .set_err_ofst = ALTR_A10_ECC_INTTEST_OFST, + .ecc_irq_handler = altr_edac_a10_ecc_irq, + .inject_fops = &altr_edac_a10_device_inject_fops, +}; + +static int __init socfpga_init_nand_ecc(void) +{ + return altr_init_a10_ecc_device_type("altr,socfpga-nand-ecc"); +} + +early_initcall(socfpga_init_nand_ecc); + +#endif /* CONFIG_EDAC_ALTERA_NAND */ + /********************* Arria10 EDAC Device Functions *************************/ static const struct of_device_id altr_edac_a10_device_of_match[] = { #ifdef CONFIG_EDAC_ALTERA_L2C @@ -1297,6 +1324,9 @@ static const struct of_device_id altr_edac_a10_device_of_match[] = { #ifdef CONFIG_EDAC_ALTERA_ETHERNET { .compatible = "altr,socfpga-eth-mac-ecc", .data = &a10_enetecc_data }, +#endif +#ifdef CONFIG_EDAC_ALTERA_NAND + { .compatible = "altr,socfpga-nand-ecc", .data = &a10_nandecc_data }, #endif {}, }; @@ -1584,15 +1614,15 @@ static int altr_edac_a10_probe(struct platform_device *pdev) for_each_child_of_node(pdev->dev.of_node, child) { if (!of_device_is_available(child)) continue; - if (of_device_is_compatible(child, "altr,socfpga-a10-l2-ecc")) - altr_edac_a10_device_add(edac, child); - else if ((of_device_is_compatible(child, - "altr,socfpga-a10-ocram-ecc")) || - (of_device_is_compatible(child, - "altr,socfpga-eth-mac-ecc"))) + + if (of_device_is_compatible(child, "altr,socfpga-a10-l2-ecc") || + of_device_is_compatible(child, "altr,socfpga-a10-ocram-ecc") || + of_device_is_compatible(child, "altr,socfpga-eth-mac-ecc") || + of_device_is_compatible(child, "altr,socfpga-nand-ecc")) + altr_edac_a10_device_add(edac, child); - else if (of_device_is_compatible(child, - "altr,sdram-edac-a10")) + + else if (of_device_is_compatible(child, "altr,sdram-edac-a10")) of_platform_populate(pdev->dev.of_node, altr_sdram_ctrl_of_match, NULL, &pdev->dev); -- cgit v1.2.3 From e8263793b7248ec78316d5915152c105e1034a28 Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Thu, 28 Jul 2016 10:03:57 +0200 Subject: EDAC, altera: Add Arria10 DMA support Add Altera Arria10 DMA FIFO memory support. Signed-off-by: Thor Thayer Cc: dinguyen@opensource.altera.com Cc: linux-arm-kernel@lists.infradead.org Cc: linux-edac Link: http://lkml.kernel.org/r/1468512408-5156-7-git-send-email-tthayer@opensource.altera.com Signed-off-by: Borislav Petkov --- drivers/edac/Kconfig | 7 +++++++ drivers/edac/altera_edac.c | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 47378b30c8c3..d1fd57ab742b 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -405,6 +405,13 @@ config EDAC_ALTERA_NAND Support for error detection and correction on the Altera NAND FIFO Memory for Altera SoCs. +config EDAC_ALTERA_DMA + bool "Altera DMA FIFO ECC" + depends on EDAC_ALTERA=y && PL330_DMA=y + help + Support for error detection and correction on the + Altera DMA FIFO Memory for Altera SoCs. + config EDAC_SYNOPSYS tristate "Synopsys DDR Memory Controller" depends on EDAC_MM_EDAC && ARCH_ZYNQ diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index fe6374236bd9..83edc6861eb1 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -1312,6 +1312,33 @@ early_initcall(socfpga_init_nand_ecc); #endif /* CONFIG_EDAC_ALTERA_NAND */ +/********************** DMA Device Functions **********************/ + +#ifdef CONFIG_EDAC_ALTERA_DMA + +static const struct edac_device_prv_data a10_dmaecc_data = { + .setup = altr_check_ecc_deps, + .ce_clear_mask = ALTR_A10_ECC_SERRPENA, + .ue_clear_mask = ALTR_A10_ECC_DERRPENA, + .dbgfs_name = "altr_trigger", + .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL, + .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, + .ce_set_mask = ALTR_A10_ECC_TSERRA, + .ue_set_mask = ALTR_A10_ECC_TDERRA, + .set_err_ofst = ALTR_A10_ECC_INTTEST_OFST, + .ecc_irq_handler = altr_edac_a10_ecc_irq, + .inject_fops = &altr_edac_a10_device_inject_fops, +}; + +static int __init socfpga_init_dma_ecc(void) +{ + return altr_init_a10_ecc_device_type("altr,socfpga-dma-ecc"); +} + +early_initcall(socfpga_init_dma_ecc); + +#endif /* CONFIG_EDAC_ALTERA_DMA */ + /********************* Arria10 EDAC Device Functions *************************/ static const struct of_device_id altr_edac_a10_device_of_match[] = { #ifdef CONFIG_EDAC_ALTERA_L2C @@ -1327,6 +1354,9 @@ static const struct of_device_id altr_edac_a10_device_of_match[] = { #endif #ifdef CONFIG_EDAC_ALTERA_NAND { .compatible = "altr,socfpga-nand-ecc", .data = &a10_nandecc_data }, +#endif +#ifdef CONFIG_EDAC_ALTERA_DMA + { .compatible = "altr,socfpga-dma-ecc", .data = &a10_dmaecc_data }, #endif {}, }; @@ -1618,7 +1648,8 @@ static int altr_edac_a10_probe(struct platform_device *pdev) if (of_device_is_compatible(child, "altr,socfpga-a10-l2-ecc") || of_device_is_compatible(child, "altr,socfpga-a10-ocram-ecc") || of_device_is_compatible(child, "altr,socfpga-eth-mac-ecc") || - of_device_is_compatible(child, "altr,socfpga-nand-ecc")) + of_device_is_compatible(child, "altr,socfpga-nand-ecc") || + of_device_is_compatible(child, "altr,socfpga-dma-ecc")) altr_edac_a10_device_add(edac, child); -- cgit v1.2.3 From c609581d1f75e6965db8258015f5ae357df477c8 Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Thu, 14 Jul 2016 11:06:45 -0500 Subject: EDAC, altera: Add Arria10 USB support Add Altera Arria10 USB FIFO memory support. Signed-off-by: Thor Thayer Cc: dinguyen@opensource.altera.com Cc: linux-arm-kernel@lists.infradead.org Cc: linux-edac Link: http://lkml.kernel.org/r/1468512408-5156-8-git-send-email-tthayer@opensource.altera.com Signed-off-by: Borislav Petkov --- drivers/edac/Kconfig | 7 +++++++ drivers/edac/altera_edac.c | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index d1fd57ab742b..1966068f583b 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -412,6 +412,13 @@ config EDAC_ALTERA_DMA Support for error detection and correction on the Altera DMA FIFO Memory for Altera SoCs. +config EDAC_ALTERA_USB + bool "Altera USB FIFO ECC" + depends on EDAC_ALTERA=y && USB_DWC2 + help + Support for error detection and correction on the + Altera USB FIFO Memory for Altera SoCs. + config EDAC_SYNOPSYS tristate "Synopsys DDR Memory Controller" depends on EDAC_MM_EDAC && ARCH_ZYNQ diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 83edc6861eb1..84798536b6a8 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -1339,6 +1339,33 @@ early_initcall(socfpga_init_dma_ecc); #endif /* CONFIG_EDAC_ALTERA_DMA */ +/********************** USB Device Functions **********************/ + +#ifdef CONFIG_EDAC_ALTERA_USB + +static const struct edac_device_prv_data a10_usbecc_data = { + .setup = altr_check_ecc_deps, + .ce_clear_mask = ALTR_A10_ECC_SERRPENA, + .ue_clear_mask = ALTR_A10_ECC_DERRPENA, + .dbgfs_name = "altr_trigger", + .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL, + .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, + .ce_set_mask = ALTR_A10_ECC_TSERRA, + .ue_set_mask = ALTR_A10_ECC_TDERRA, + .set_err_ofst = ALTR_A10_ECC_INTTEST_OFST, + .ecc_irq_handler = altr_edac_a10_ecc_irq, + .inject_fops = &altr_edac_a10_device_inject_fops, +}; + +static int __init socfpga_init_usb_ecc(void) +{ + return altr_init_a10_ecc_device_type("altr,socfpga-usb-ecc"); +} + +early_initcall(socfpga_init_usb_ecc); + +#endif /* CONFIG_EDAC_ALTERA_USB */ + /********************* Arria10 EDAC Device Functions *************************/ static const struct of_device_id altr_edac_a10_device_of_match[] = { #ifdef CONFIG_EDAC_ALTERA_L2C @@ -1357,6 +1384,9 @@ static const struct of_device_id altr_edac_a10_device_of_match[] = { #endif #ifdef CONFIG_EDAC_ALTERA_DMA { .compatible = "altr,socfpga-dma-ecc", .data = &a10_dmaecc_data }, +#endif +#ifdef CONFIG_EDAC_ALTERA_USB + { .compatible = "altr,socfpga-usb-ecc", .data = &a10_usbecc_data }, #endif {}, }; @@ -1649,7 +1679,8 @@ static int altr_edac_a10_probe(struct platform_device *pdev) of_device_is_compatible(child, "altr,socfpga-a10-ocram-ecc") || of_device_is_compatible(child, "altr,socfpga-eth-mac-ecc") || of_device_is_compatible(child, "altr,socfpga-nand-ecc") || - of_device_is_compatible(child, "altr,socfpga-dma-ecc")) + of_device_is_compatible(child, "altr,socfpga-dma-ecc") || + of_device_is_compatible(child, "altr,socfpga-usb-ecc")) altr_edac_a10_device_add(edac, child); -- cgit v1.2.3 From 485fe9e24e53fbeef7594e90eed1e09e23b9c184 Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Thu, 14 Jul 2016 11:06:46 -0500 Subject: EDAC, altera: Add Arria10 QSPI support Add Altera Arria10 QSPI FIFO memory support. Signed-off-by: Thor Thayer Cc: dinguyen@opensource.altera.com Cc: linux-arm-kernel@lists.infradead.org Cc: linux-edac Link: http://lkml.kernel.org/r/1468512408-5156-9-git-send-email-tthayer@opensource.altera.com Signed-off-by: Borislav Petkov --- drivers/edac/Kconfig | 7 +++++++ drivers/edac/altera_edac.c | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 1966068f583b..72752f460cbb 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -419,6 +419,13 @@ config EDAC_ALTERA_USB Support for error detection and correction on the Altera USB FIFO Memory for Altera SoCs. +config EDAC_ALTERA_QSPI + bool "Altera QSPI FIFO ECC" + depends on EDAC_ALTERA=y && SPI_CADENCE_QUADSPI + help + Support for error detection and correction on the + Altera QSPI FIFO Memory for Altera SoCs. + config EDAC_SYNOPSYS tristate "Synopsys DDR Memory Controller" depends on EDAC_MM_EDAC && ARCH_ZYNQ diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 84798536b6a8..28247f82e1d5 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -1366,6 +1366,33 @@ early_initcall(socfpga_init_usb_ecc); #endif /* CONFIG_EDAC_ALTERA_USB */ +/********************** QSPI Device Functions **********************/ + +#ifdef CONFIG_EDAC_ALTERA_QSPI + +static const struct edac_device_prv_data a10_qspiecc_data = { + .setup = altr_check_ecc_deps, + .ce_clear_mask = ALTR_A10_ECC_SERRPENA, + .ue_clear_mask = ALTR_A10_ECC_DERRPENA, + .dbgfs_name = "altr_trigger", + .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL, + .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, + .ce_set_mask = ALTR_A10_ECC_TSERRA, + .ue_set_mask = ALTR_A10_ECC_TDERRA, + .set_err_ofst = ALTR_A10_ECC_INTTEST_OFST, + .ecc_irq_handler = altr_edac_a10_ecc_irq, + .inject_fops = &altr_edac_a10_device_inject_fops, +}; + +static int __init socfpga_init_qspi_ecc(void) +{ + return altr_init_a10_ecc_device_type("altr,socfpga-qspi-ecc"); +} + +early_initcall(socfpga_init_qspi_ecc); + +#endif /* CONFIG_EDAC_ALTERA_QSPI */ + /********************* Arria10 EDAC Device Functions *************************/ static const struct of_device_id altr_edac_a10_device_of_match[] = { #ifdef CONFIG_EDAC_ALTERA_L2C @@ -1387,6 +1414,9 @@ static const struct of_device_id altr_edac_a10_device_of_match[] = { #endif #ifdef CONFIG_EDAC_ALTERA_USB { .compatible = "altr,socfpga-usb-ecc", .data = &a10_usbecc_data }, +#endif +#ifdef CONFIG_EDAC_ALTERA_QSPI + { .compatible = "altr,socfpga-qspi-ecc", .data = &a10_qspiecc_data }, #endif {}, }; @@ -1680,7 +1710,8 @@ static int altr_edac_a10_probe(struct platform_device *pdev) of_device_is_compatible(child, "altr,socfpga-eth-mac-ecc") || of_device_is_compatible(child, "altr,socfpga-nand-ecc") || of_device_is_compatible(child, "altr,socfpga-dma-ecc") || - of_device_is_compatible(child, "altr,socfpga-usb-ecc")) + of_device_is_compatible(child, "altr,socfpga-usb-ecc") || + of_device_is_compatible(child, "altr,socfpga-qspi-ecc")) altr_edac_a10_device_add(edac, child); -- cgit v1.2.3 From 15ef94f4eeab70184b5c73a952d1b4defa4a57ab Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Thu, 14 Jul 2016 11:06:47 -0500 Subject: ARM: dts: Add Arria10 DMA EDAC devicetree entry Add the device tree entries needed to support the Altera DMA FIFO buffer EDAC on the Arria10 chip. Signed-off-by: Thor Thayer Acked-by: Dinh Nguyen Cc: devicetree@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-edac Link: http://lkml.kernel.org/r/1468512408-5156-10-git-send-email-tthayer@opensource.altera.com Signed-off-by: Borislav Petkov --- arch/arm/boot/dts/socfpga_arria10.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/socfpga_arria10.dtsi b/arch/arm/boot/dts/socfpga_arria10.dtsi index 94000cbe576b..50bcaaa6da39 100644 --- a/arch/arm/boot/dts/socfpga_arria10.dtsi +++ b/arch/arm/boot/dts/socfpga_arria10.dtsi @@ -639,6 +639,14 @@ interrupts = <5 IRQ_TYPE_LEVEL_HIGH>, <37 IRQ_TYPE_LEVEL_HIGH>; }; + + dma-ecc@ff8c8000 { + compatible = "altr,socfpga-dma-ecc"; + reg = <0xff8c8000 0x400>; + altr,ecc-parent = <&pdma>; + interrupts = <10 IRQ_TYPE_LEVEL_HIGH>, + <42 IRQ_TYPE_LEVEL_HIGH>; + }; }; rst: rstmgr@ffd05000 { -- cgit v1.2.3 From 7c51d98de6c85b8e4e96058db1c7ac3d6007d204 Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Thu, 14 Jul 2016 11:06:48 -0500 Subject: ARM: dts: Add Arria10 USB EDAC devicetree entry Add the device tree entries needed to support the Altera USB FIFO buffer EDAC on the Arria10 chip. Signed-off-by: Thor Thayer Acked-by: Dinh Nguyen Cc: devicetree@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-edac Link: http://lkml.kernel.org/r/1468512408-5156-11-git-send-email-tthayer@opensource.altera.com Signed-off-by: Borislav Petkov --- arch/arm/boot/dts/socfpga_arria10.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/socfpga_arria10.dtsi b/arch/arm/boot/dts/socfpga_arria10.dtsi index 50bcaaa6da39..f520cbff5e1c 100644 --- a/arch/arm/boot/dts/socfpga_arria10.dtsi +++ b/arch/arm/boot/dts/socfpga_arria10.dtsi @@ -647,6 +647,14 @@ interrupts = <10 IRQ_TYPE_LEVEL_HIGH>, <42 IRQ_TYPE_LEVEL_HIGH>; }; + + usb0-ecc@ff8c8800 { + compatible = "altr,socfpga-usb-ecc"; + reg = <0xff8c8800 0x400>; + altr,ecc-parent = <&usb0>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>, + <34 IRQ_TYPE_LEVEL_HIGH>; + }; }; rst: rstmgr@ffd05000 { -- cgit v1.2.3 From dc0a50a8411e2a3a3ca5a9d97581bbc5420c2687 Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Wed, 3 Aug 2016 10:59:15 -0400 Subject: EDAC, amd64: Fix channel decode on Fam15hMod60h systems Fam15hMod60h systems are using the channel decode of Fam15hMod30h which gives incorrect results. Fam15hMod60h systems should use the generic channel decode method plus a couple more cases. Signed-off-by: Yazen Ghannam Cc: Aravind Gopalakrishnan Cc: linux-edac Link: http://lkml.kernel.org/r/1470236355-30039-1-git-send-email-Yazen.Ghannam@amd.com Signed-off-by: Borislav Petkov --- drivers/edac/amd64_edac.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 8c0ec2128907..da43404dbd0c 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, if (intlv_addr & 0x2) { u8 shift = intlv_addr & 0x1 ? 9 : 6; - u32 temp = hweight_long((u32) ((sys_addr >> 16) & 0x1F)) % 2; + u32 temp = hweight_long((u32) ((sys_addr >> 16) & 0x1F)) & 1; return ((sys_addr >> shift) & 1) ^ temp; } + if (intlv_addr & 0x4) { + u8 shift = intlv_addr & 0x1 ? 9 : 8; + + return (sys_addr >> shift) & 1; + } + return (sys_addr >> (12 + hweight8(intlv_en))) & 1; } @@ -1726,8 +1732,11 @@ static int f15_m30h_match_to_this_node(struct amd64_pvt *pvt, unsigned range, if (!(num_dcts_intlv % 2 == 0) || (num_dcts_intlv > 4)) return -EINVAL; - channel = f15_m30h_determine_channel(pvt, sys_addr, intlv_en, - num_dcts_intlv, dct_sel); + if (pvt->model >= 0x60) + channel = f1x_determine_channel(pvt, sys_addr, false, intlv_en); + else + channel = f15_m30h_determine_channel(pvt, sys_addr, intlv_en, + num_dcts_intlv, dct_sel); /* Verify we stay within the MAX number of channels allowed */ if (channel > 3) -- cgit v1.2.3 From 5e40cd4d258cc0728585a94fd81f73488f7cdce7 Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Tue, 2 Aug 2016 10:56:19 -0500 Subject: Documentation: dt: socfpga: Add Arria10 SD-MMC EDAC binding Add the device tree bindings needed to support the Altera SD-MMC FIFO buffers EDAC on the Arria10 chip. Signed-off-by: Thor Thayer Acked-by: Rob Herring Cc: devicetree@vger.kernel.org Cc: dinguyen@opensource.altera.com Cc: linux-arm-kernel@lists.infradead.org Cc: linux-edac Link: http://lkml.kernel.org/r/1470153381-20517-2-git-send-email-tthayer@opensource.altera.com Signed-off-by: Borislav Petkov --- .../devicetree/bindings/arm/altera/socfpga-eccmgr.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt b/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt index ee66df082a42..4a1714f96bab 100644 --- a/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt +++ b/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt @@ -122,6 +122,15 @@ Required Properties: - interrupts : Should be single bit error interrupt, then double bit error interrupt, in this order. +SDMMC FIFO ECC +Required Properties: +- compatible : Should be "altr,socfpga-sdmmc-ecc" +- reg : Address and size for ECC block registers. +- altr,ecc-parent : phandle to parent SD/MMC node. +- interrupts : Should be single bit error interrupt, then double bit error + interrupt, in this order for port A, and then single bit error interrupt, + then double bit error interrupt in this order for port B. + Example: eccmgr: eccmgr@ffd06000 { @@ -211,4 +220,14 @@ Example: interrupts = <14 IRQ_TYPE_LEVEL_HIGH>, <46 IRQ_TYPE_LEVEL_HIGH>; }; + + sdmmc-ecc@ff8c2c00 { + compatible = "altr,socfpga-sdmmc-ecc"; + reg = <0xff8c2c00 0x400>; + altr,ecc-parent = <&mmc>; + interrupts = <15 IRQ_TYPE_LEVEL_HIGH>, + <47 IRQ_TYPE_LEVEL_HIGH>, + <16 IRQ_TYPE_LEVEL_HIGH>, + <48 IRQ_TYPE_LEVEL_HIGH>; + }; }; -- cgit v1.2.3 From 911049845d7096c27304930ff478cbf3f2623ba3 Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Tue, 9 Aug 2016 09:40:52 -0500 Subject: EDAC, altera: Add Arria10 SD-MMC EDAC support Add Altera Arria10 SD-MMC FIFO memory EDAC support. The SD-MMC is a dual port RAM implementation which is different than any of the other peripherals and therefore requires additional code. Signed-off-by: Thor Thayer Cc: dinguyen@opensource.altera.com Cc: linux-arm-kernel@lists.infradead.org Cc: linux-edac Link: http://lkml.kernel.org/r/1470753653-23465-3-git-send-email-tthayer@opensource.altera.com Signed-off-by: Borislav Petkov --- drivers/edac/Kconfig | 7 ++ drivers/edac/altera_edac.c | 188 ++++++++++++++++++++++++++++++++++++++++++++- drivers/edac/altera_edac.h | 5 ++ 3 files changed, 199 insertions(+), 1 deletion(-) diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 72752f460cbb..394cd16dd58f 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -426,6 +426,13 @@ config EDAC_ALTERA_QSPI Support for error detection and correction on the Altera QSPI FIFO Memory for Altera SoCs. +config EDAC_ALTERA_SDMMC + bool "Altera SDMMC FIFO ECC" + depends on EDAC_ALTERA=y && MMC_DW + help + Support for error detection and correction on the + Altera SDMMC FIFO Memory for Altera SoCs. + config EDAC_SYNOPSYS tristate "Synopsys DDR Memory Controller" depends on EDAC_MM_EDAC && ARCH_ZYNQ diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 28247f82e1d5..efaf727be25a 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -1393,6 +1393,188 @@ early_initcall(socfpga_init_qspi_ecc); #endif /* CONFIG_EDAC_ALTERA_QSPI */ +/********************* SDMMC Device Functions **********************/ + +#ifdef CONFIG_EDAC_ALTERA_SDMMC + +static const struct edac_device_prv_data a10_sdmmceccb_data; +static int altr_portb_setup(struct altr_edac_device_dev *device) +{ + struct edac_device_ctl_info *dci; + struct altr_edac_device_dev *altdev; + char *ecc_name = "sdmmcb-ecc"; + int edac_idx, rc; + struct device_node *np; + const struct edac_device_prv_data *prv = &a10_sdmmceccb_data; + + rc = altr_check_ecc_deps(device); + if (rc) + return rc; + + np = of_find_compatible_node(NULL, NULL, "altr,socfpga-sdmmc-ecc"); + if (!np) { + edac_printk(KERN_WARNING, EDAC_DEVICE, "SDMMC node not found\n"); + return -ENODEV; + } + + /* Create the PortB EDAC device */ + edac_idx = edac_device_alloc_index(); + dci = edac_device_alloc_ctl_info(sizeof(*altdev), ecc_name, 1, + ecc_name, 1, 0, NULL, 0, edac_idx); + if (!dci) { + edac_printk(KERN_ERR, EDAC_DEVICE, + "%s: Unable to allocate PortB EDAC device\n", + ecc_name); + return -ENOMEM; + } + + /* Initialize the PortB EDAC device structure from PortA structure */ + altdev = dci->pvt_info; + *altdev = *device; + + if (!devres_open_group(&altdev->ddev, altr_portb_setup, GFP_KERNEL)) + return -ENOMEM; + + /* Update PortB specific values */ + altdev->edac_dev_name = ecc_name; + altdev->edac_idx = edac_idx; + altdev->edac_dev = dci; + altdev->data = prv; + dci->dev = &altdev->ddev; + dci->ctl_name = "Altera ECC Manager"; + dci->mod_name = ecc_name; + dci->dev_name = ecc_name; + + /* Update the IRQs for PortB */ + altdev->sb_irq = irq_of_parse_and_map(np, 2); + if (!altdev->sb_irq) { + edac_printk(KERN_ERR, EDAC_DEVICE, "Error PortB SBIRQ alloc\n"); + rc = -ENODEV; + goto err_release_group_1; + } + rc = devm_request_irq(&altdev->ddev, altdev->sb_irq, + prv->ecc_irq_handler, + IRQF_SHARED, ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "PortB SBERR IRQ error\n"); + goto err_release_group_1; + } + + altdev->db_irq = irq_of_parse_and_map(np, 3); + if (!altdev->db_irq) { + edac_printk(KERN_ERR, EDAC_DEVICE, "Error PortB DBIRQ alloc\n"); + rc = -ENODEV; + goto err_release_group_1; + } + rc = devm_request_irq(&altdev->ddev, altdev->db_irq, + prv->ecc_irq_handler, + IRQF_SHARED, ecc_name, altdev); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, "PortB DBERR IRQ error\n"); + goto err_release_group_1; + } + + rc = edac_device_add_device(dci); + if (rc) { + edac_printk(KERN_ERR, EDAC_DEVICE, + "edac_device_add_device portB failed\n"); + rc = -ENOMEM; + goto err_release_group_1; + } + altr_create_edacdev_dbgfs(dci, prv); + + list_add(&altdev->next, &altdev->edac->a10_ecc_devices); + + devres_remove_group(&altdev->ddev, altr_portb_setup); + + return 0; + +err_release_group_1: + edac_device_free_ctl_info(dci); + devres_release_group(&altdev->ddev, altr_portb_setup); + edac_printk(KERN_ERR, EDAC_DEVICE, + "%s:Error setting up EDAC device: %d\n", ecc_name, rc); + return rc; +} + +static irqreturn_t altr_edac_a10_ecc_irq_portb(int irq, void *dev_id) +{ + struct altr_edac_device_dev *ad = dev_id; + void __iomem *base = ad->base; + const struct edac_device_prv_data *priv = ad->data; + + if (irq == ad->sb_irq) { + writel(priv->ce_clear_mask, + base + ALTR_A10_ECC_INTSTAT_OFST); + edac_device_handle_ce(ad->edac_dev, 0, 0, ad->edac_dev_name); + return IRQ_HANDLED; + } else if (irq == ad->db_irq) { + writel(priv->ue_clear_mask, + base + ALTR_A10_ECC_INTSTAT_OFST); + edac_device_handle_ue(ad->edac_dev, 0, 0, ad->edac_dev_name); + return IRQ_HANDLED; + } + + WARN_ONCE(1, "Unhandled IRQ%d on Port B.", irq); + + return IRQ_NONE; +} + +static const struct edac_device_prv_data a10_sdmmcecca_data = { + .setup = altr_portb_setup, + .ce_clear_mask = ALTR_A10_ECC_SERRPENA, + .ue_clear_mask = ALTR_A10_ECC_DERRPENA, + .dbgfs_name = "altr_trigger", + .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL, + .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, + .ce_set_mask = ALTR_A10_ECC_SERRPENA, + .ue_set_mask = ALTR_A10_ECC_DERRPENA, + .set_err_ofst = ALTR_A10_ECC_INTTEST_OFST, + .ecc_irq_handler = altr_edac_a10_ecc_irq, + .inject_fops = &altr_edac_a10_device_inject_fops, +}; + +static const struct edac_device_prv_data a10_sdmmceccb_data = { + .setup = altr_portb_setup, + .ce_clear_mask = ALTR_A10_ECC_SERRPENB, + .ue_clear_mask = ALTR_A10_ECC_DERRPENB, + .dbgfs_name = "altr_trigger", + .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL, + .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, + .ce_set_mask = ALTR_A10_ECC_TSERRB, + .ue_set_mask = ALTR_A10_ECC_TDERRB, + .set_err_ofst = ALTR_A10_ECC_INTTEST_OFST, + .ecc_irq_handler = altr_edac_a10_ecc_irq_portb, + .inject_fops = &altr_edac_a10_device_inject_fops, +}; + +static int __init socfpga_init_sdmmc_ecc(void) +{ + int rc = -ENODEV; + struct device_node *child = of_find_compatible_node(NULL, NULL, + "altr,socfpga-sdmmc-ecc"); + if (!child) { + edac_printk(KERN_WARNING, EDAC_DEVICE, "SDMMC node not found\n"); + return -ENODEV; + } + + if (!of_device_is_available(child)) + goto exit; + + if (validate_parent_available(child)) + goto exit; + + rc = altr_init_a10_ecc_block(child, ALTR_A10_SDMMC_IRQ_MASK, + a10_sdmmcecca_data.ecc_enable_mask, 1); +exit: + of_node_put(child); + return rc; +} + +early_initcall(socfpga_init_sdmmc_ecc); + +#endif /* CONFIG_EDAC_ALTERA_SDMMC */ + /********************* Arria10 EDAC Device Functions *************************/ static const struct of_device_id altr_edac_a10_device_of_match[] = { #ifdef CONFIG_EDAC_ALTERA_L2C @@ -1417,6 +1599,9 @@ static const struct of_device_id altr_edac_a10_device_of_match[] = { #endif #ifdef CONFIG_EDAC_ALTERA_QSPI { .compatible = "altr,socfpga-qspi-ecc", .data = &a10_qspiecc_data }, +#endif +#ifdef CONFIG_EDAC_ALTERA_SDMMC + { .compatible = "altr,socfpga-sdmmc-ecc", .data = &a10_sdmmcecca_data }, #endif {}, }; @@ -1711,7 +1896,8 @@ static int altr_edac_a10_probe(struct platform_device *pdev) of_device_is_compatible(child, "altr,socfpga-nand-ecc") || of_device_is_compatible(child, "altr,socfpga-dma-ecc") || of_device_is_compatible(child, "altr,socfpga-usb-ecc") || - of_device_is_compatible(child, "altr,socfpga-qspi-ecc")) + of_device_is_compatible(child, "altr,socfpga-qspi-ecc") || + of_device_is_compatible(child, "altr,socfpga-sdmmc-ecc")) altr_edac_a10_device_add(edac, child); diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h index 687d8e754d36..cf3a68bec100 100644 --- a/drivers/edac/altera_edac.h +++ b/drivers/edac/altera_edac.h @@ -250,6 +250,8 @@ struct altr_sdram_mc_data { #define ALTR_A10_ECC_INTTEST_OFST 0x24 #define ALTR_A10_ECC_TSERRA BIT(0) #define ALTR_A10_ECC_TDERRA BIT(8) +#define ALTR_A10_ECC_TSERRB BIT(16) +#define ALTR_A10_ECC_TDERRB BIT(24) /* ECC Manager Defines */ #define A10_SYSMGR_ECC_INTMASK_SET_OFST 0x94 @@ -288,6 +290,9 @@ struct altr_sdram_mc_data { /* Arria 10 Ethernet ECC Management Group Defines */ #define ALTR_A10_COMMON_ECC_EN_CTL BIT(0) +/* Arria 10 SDMMC ECC Management Group Defines */ +#define ALTR_A10_SDMMC_IRQ_MASK (BIT(16) | BIT(15)) + /* A10 ECC Controller memory initialization timeout */ #define ALTR_A10_ECC_INIT_WATCHDOG_10US 10000 -- cgit v1.2.3 From 03fc6ea97f02006ea4dbc1e9f1e8ccba6fe58656 Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Tue, 9 Aug 2016 09:40:53 -0500 Subject: ARM: dts: Add Arria10 SD/MMC EDAC devicetree entry Add the device tree entries needed to support the Altera SD/MMC FIFO buffer EDAC on the Arria10 chip. Signed-off-by: Thor Thayer Acked-by: Dinh Nguyen Cc: devicetree@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-edac Link: http://lkml.kernel.org/r/1470753653-23465-4-git-send-email-tthayer@opensource.altera.com Signed-off-by: Borislav Petkov --- arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts | 12 ++++++++++++ 1 file changed, 12 insertions(+) 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 @@ broken-cd; bus-width = <4>; }; + +&eccmgr { + sdmmca-ecc@ff8c2c00 { + compatible = "altr,socfpga-sdmmc-ecc"; + reg = <0xff8c2c00 0x400>; + altr,ecc-parent = <&mmc>; + interrupts = <15 IRQ_TYPE_LEVEL_HIGH>, + <47 IRQ_TYPE_LEVEL_HIGH>, + <16 IRQ_TYPE_LEVEL_HIGH>, + <48 IRQ_TYPE_LEVEL_HIGH>; + }; +}; -- cgit v1.2.3 From 9bcd919eb84224aee2a5ed4fa33ed80aabfe0343 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 10 Aug 2016 13:44:27 +0000 Subject: EDAC, altera: Make a10_eccmgr_ic_ops static Fix the following sparse warning: drivers/edac/altera_edac.c:1649:23: warning: symbol 'a10_eccmgr_ic_ops' was not declared. Should it be static? Signed-off-by: Wei Yongjun Reviewed-by: Thor Thayer Cc: linux-edac Cc: lkml Link: http://lkml.kernel.org/r/1470836667-11822-1-git-send-email-weiyj.lk@gmail.com Signed-off-by: Borislav Petkov --- drivers/edac/altera_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index efaf727be25a..c8147f1d9edd 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -1831,7 +1831,7 @@ static int a10_eccmgr_irqdomain_map(struct irq_domain *d, unsigned int irq, return 0; } -struct irq_domain_ops a10_eccmgr_ic_ops = { +static struct irq_domain_ops a10_eccmgr_ic_ops = { .map = a10_eccmgr_irqdomain_map, .xlate = irq_domain_xlate_twocell, }; -- cgit v1.2.3 From 7bb8b777794bdeb9e53b3c0f39ed5474930a062a Mon Sep 17 00:00:00 2001 From: Bhaktipriya Shridhar Date: Sat, 13 Aug 2016 22:11:24 +0530 Subject: EDAC, wq: Remove deprecated create_singlethread_workqueue() Replace the deprecated create_singlethread_workqueue() with alloc_ordered_workqueue() with WQ_MEM_RECLAIM. This is the identity conversion. It's not recommended to stall it from memory pressure. Hence, WQ_MEM_RECLAIM has been set to ensure forward progress under memory pressure. Signed-off-by: Bhaktipriya Shridhar Cc: Tejun Heo Cc: linux-edac Link: http://lkml.kernel.org/r/20160813164124.GA9077@Karyakshetra Signed-off-by: Borislav Petkov --- drivers/edac/wq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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); int edac_workqueue_setup(void) { - wq = create_singlethread_workqueue("edac-poller"); + wq = alloc_ordered_workqueue("edac-poller", WQ_MEM_RECLAIM); if (!wq) return -ENODEV; else -- cgit v1.2.3 From 6fa06b0d9e9514bfca9b89493161f2a2cbb079a9 Mon Sep 17 00:00:00 2001 From: Tillmann Heidsieck Date: Mon, 15 Aug 2016 21:08:49 +0200 Subject: EDAC, mpc85xx: Fix PCIe error capture According to the reference manual of MPC8572 and T4240, bit 31 of PEX_ERR_CAP_STAT is W1C (write 1 to clear). Add the corresponding write to PEX_ERR_CAP_STAT in order to fix the PCIe error capture. Tested on a T4240 processor. Signed-off-by: Tillmann Heidsieck Acked-by: Johannes Thumshirn Cc: linux-edac Link: http://lkml.kernel.org/r/20160815190849.29327-1-theidsieck@leenox.de Signed-off-by: Borislav Petkov --- drivers/edac/mpc85xx_edac.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index ca63d0da8889..f5283f5c07cb 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -187,14 +187,14 @@ static void mpc85xx_pci_check(struct edac_pci_ctl_info *pci) static void mpc85xx_pcie_check(struct edac_pci_ctl_info *pci) { struct mpc85xx_pci_pdata *pdata = pci->pvt_info; - u32 err_detect; + u32 err_detect, err_cap_stat; err_detect = in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR); + err_cap_stat = in_be32(pdata->pci_vbase + MPC85XX_PCI_GAS_TIMR); pr_err("PCIe error(s) detected\n"); pr_err("PCIe ERR_DR register: 0x%08x\n", err_detect); - pr_err("PCIe ERR_CAP_STAT register: 0x%08x\n", - in_be32(pdata->pci_vbase + MPC85XX_PCI_GAS_TIMR)); + pr_err("PCIe ERR_CAP_STAT register: 0x%08x\n", err_cap_stat); pr_err("PCIe ERR_CAP_R0 register: 0x%08x\n", in_be32(pdata->pci_vbase + MPC85XX_PCIE_ERR_CAP_R0)); pr_err("PCIe ERR_CAP_R1 register: 0x%08x\n", @@ -206,6 +206,9 @@ static void mpc85xx_pcie_check(struct edac_pci_ctl_info *pci) /* clear error bits */ out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, err_detect); + + /* reset error capture */ + out_be32(pdata->pci_vbase + MPC85XX_PCI_GAS_TIMR, err_cap_stat | 0x1); } static int mpc85xx_pcie_find_capability(struct device_node *np) @@ -344,6 +347,9 @@ static int mpc85xx_pci_err_probe(struct platform_device *op) /* clear error bits */ out_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DR, ~0); + /* reset error capture */ + out_be32(pdata->pci_vbase + MPC85XX_PCI_GAS_TIMR, 0x1); + if (edac_pci_add_device(pci, pdata->edac_idx) > 0) { edac_dbg(3, "failed edac_pci_add_device()\n"); goto err; -- cgit v1.2.3 From f399f34bdb448ca309e8fe9dd2eb04cdfd788e0a Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Fri, 19 Aug 2016 11:04:25 -0500 Subject: EDAC, altera: Rename device trigger to common name The L2 and OCRAM devices have different ecc trigger names than the other EDAC devices (FIFO peripherals). Make them all the same and remove the character array from the device structure. Signed-off-by: Thor Thayer Cc: linux-edac Link: http://lkml.kernel.org/r/1471622666-15197-2-git-send-email-tthayer@opensource.altera.com Signed-off-by: Borislav Petkov --- drivers/edac/altera_edac.c | 13 +------------ drivers/edac/altera_edac.h | 1 - 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index c8147f1d9edd..06a46260d36e 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -680,7 +680,7 @@ static void altr_create_edacdev_dbgfs(struct edac_device_ctl_info *edac_dci, if (!drvdata->debugfs_dir) return; - if (!edac_debugfs_create_file(priv->dbgfs_name, S_IWUSR, + if (!edac_debugfs_create_file("altr_trigger", S_IWUSR, drvdata->debugfs_dir, edac_dci, priv->inject_fops)) debugfs_remove_recursive(drvdata->debugfs_dir); @@ -1108,7 +1108,6 @@ static const struct edac_device_prv_data ocramecc_data = { .setup = altr_check_ecc_deps, .ce_clear_mask = (ALTR_OCR_ECC_EN | ALTR_OCR_ECC_SERR), .ue_clear_mask = (ALTR_OCR_ECC_EN | ALTR_OCR_ECC_DERR), - .dbgfs_name = "altr_ocram_trigger", .alloc_mem = ocram_alloc_mem, .free_mem = ocram_free_mem, .ecc_enable_mask = ALTR_OCR_ECC_EN, @@ -1125,7 +1124,6 @@ static const struct edac_device_prv_data a10_ocramecc_data = { .ce_clear_mask = ALTR_A10_ECC_SERRPENA, .ue_clear_mask = ALTR_A10_ECC_DERRPENA, .irq_status_mask = A10_SYSMGR_ECC_INTSTAT_OCRAM, - .dbgfs_name = "altr_ocram_trigger", .ecc_enable_mask = ALTR_A10_OCRAM_ECC_EN_CTL, .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, .ce_set_mask = ALTR_A10_ECC_TSERRA, @@ -1228,7 +1226,6 @@ static const struct edac_device_prv_data l2ecc_data = { .setup = altr_l2_check_deps, .ce_clear_mask = 0, .ue_clear_mask = 0, - .dbgfs_name = "altr_l2_trigger", .alloc_mem = l2_alloc_mem, .free_mem = l2_free_mem, .ecc_enable_mask = ALTR_L2_ECC_EN, @@ -1244,7 +1241,6 @@ static const struct edac_device_prv_data a10_l2ecc_data = { .ce_clear_mask = ALTR_A10_L2_ECC_SERR_CLR, .ue_clear_mask = ALTR_A10_L2_ECC_MERR_CLR, .irq_status_mask = A10_SYSMGR_ECC_INTSTAT_L2, - .dbgfs_name = "altr_l2_trigger", .alloc_mem = l2_alloc_mem, .free_mem = l2_free_mem, .ecc_enable_mask = ALTR_A10_L2_ECC_EN_CTL, @@ -1266,7 +1262,6 @@ static const struct edac_device_prv_data a10_enetecc_data = { .setup = altr_check_ecc_deps, .ce_clear_mask = ALTR_A10_ECC_SERRPENA, .ue_clear_mask = ALTR_A10_ECC_DERRPENA, - .dbgfs_name = "altr_trigger", .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL, .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, .ce_set_mask = ALTR_A10_ECC_TSERRA, @@ -1293,7 +1288,6 @@ static const struct edac_device_prv_data a10_nandecc_data = { .setup = altr_check_ecc_deps, .ce_clear_mask = ALTR_A10_ECC_SERRPENA, .ue_clear_mask = ALTR_A10_ECC_DERRPENA, - .dbgfs_name = "altr_trigger", .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL, .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, .ce_set_mask = ALTR_A10_ECC_TSERRA, @@ -1320,7 +1314,6 @@ static const struct edac_device_prv_data a10_dmaecc_data = { .setup = altr_check_ecc_deps, .ce_clear_mask = ALTR_A10_ECC_SERRPENA, .ue_clear_mask = ALTR_A10_ECC_DERRPENA, - .dbgfs_name = "altr_trigger", .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL, .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, .ce_set_mask = ALTR_A10_ECC_TSERRA, @@ -1347,7 +1340,6 @@ static const struct edac_device_prv_data a10_usbecc_data = { .setup = altr_check_ecc_deps, .ce_clear_mask = ALTR_A10_ECC_SERRPENA, .ue_clear_mask = ALTR_A10_ECC_DERRPENA, - .dbgfs_name = "altr_trigger", .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL, .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, .ce_set_mask = ALTR_A10_ECC_TSERRA, @@ -1374,7 +1366,6 @@ static const struct edac_device_prv_data a10_qspiecc_data = { .setup = altr_check_ecc_deps, .ce_clear_mask = ALTR_A10_ECC_SERRPENA, .ue_clear_mask = ALTR_A10_ECC_DERRPENA, - .dbgfs_name = "altr_trigger", .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL, .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, .ce_set_mask = ALTR_A10_ECC_TSERRA, @@ -1524,7 +1515,6 @@ static const struct edac_device_prv_data a10_sdmmcecca_data = { .setup = altr_portb_setup, .ce_clear_mask = ALTR_A10_ECC_SERRPENA, .ue_clear_mask = ALTR_A10_ECC_DERRPENA, - .dbgfs_name = "altr_trigger", .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL, .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, .ce_set_mask = ALTR_A10_ECC_SERRPENA, @@ -1538,7 +1528,6 @@ static const struct edac_device_prv_data a10_sdmmceccb_data = { .setup = altr_portb_setup, .ce_clear_mask = ALTR_A10_ECC_SERRPENB, .ue_clear_mask = ALTR_A10_ECC_DERRPENB, - .dbgfs_name = "altr_trigger", .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL, .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, .ce_set_mask = ALTR_A10_ECC_TSERRB, diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h index cf3a68bec100..cbc96290f743 100644 --- a/drivers/edac/altera_edac.h +++ b/drivers/edac/altera_edac.h @@ -303,7 +303,6 @@ struct edac_device_prv_data { int ce_clear_mask; int ue_clear_mask; int irq_status_mask; - char dbgfs_name[20]; void * (*alloc_mem)(size_t size, void **other); void (*free_mem)(void *p, size_t size, void *other); int ecc_enable_mask; -- cgit v1.2.3 From b8978badc47e86a5262cc3ed52ed92537aebd7a3 Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Fri, 19 Aug 2016 11:04:26 -0500 Subject: EDAC, altera: Rename MC trigger to common name Rename the Memory Controller debug trigger to the same common name as the EDAC devices. Signed-off-by: Thor Thayer Cc: linux-edac Link: http://lkml.kernel.org/r/1471622666-15197-3-git-send-email-tthayer@opensource.altera.com Signed-off-by: Borislav Petkov --- drivers/edac/altera_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 06a46260d36e..817e8919cfe6 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) if (!mci->debugfs) return; - edac_debugfs_create_file("inject_ctrl", S_IWUSR, mci->debugfs, mci, + edac_debugfs_create_file("altr_trigger", S_IWUSR, mci->debugfs, mci, &altr_sdr_mc_debug_inject_fops); } -- cgit v1.2.3 From 9e6a03a044da6245ade73e3565b0ec5b8959f6fd Mon Sep 17 00:00:00 2001 From: York Sun Date: Tue, 9 Aug 2016 14:55:38 -0700 Subject: EDAC, mpc85xx: Drop setting/clearing RFXE bit in HID1 On e500v1, read fault exception enable (RFXE) controls whether assertion of core_fault_in causes a machine check interrupt. Assertion of core_fault_in can result from uncorrectable data error, such as an L2 multi-bit ECC error. It can also occur from a system error if logic on the integrated device signals a fault for nonfatal errors. RFXE bit is cleared out of reset, and should be left clear for normal operation. Assertion of core_fault_in does not cause a machine check. RFXE is set specifically for RIO (Rapid IO) and PCI for book E to catch the errors by machine check. With this bit set, the EDAC driver can't get the interrupt in case of uncorrectable error. So this bit is cleared in favor of EDAC. However, the benefit of catching such uncorrectable error doesn't outweigh the other errors which may hang the system. Besides, e500v2 has different errors masked by RFXE, and e500mc doesn't support this bit. It is more reasonable to leave RFXE as is in the EDAC driver, and leave the uncorrectable errors triggering machine check for e500v1. Suggested-by: Scott Wood Signed-off-by: York Sun Cc: Johannes Thumshirn Cc: linux-edac Cc: oss@buserror.net Cc: stuart.yoder@nxp.com Link: http://lkml.kernel.org/r/1470779760-16483-2-git-send-email-york.sun@nxp.com Signed-off-by: Borislav Petkov --- drivers/edac/mpc85xx_edac.c | 40 ---------------------------------------- 1 file changed, 40 deletions(-) diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index f5283f5c07cb..39ee9267170b 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -46,9 +46,6 @@ static u32 orig_pci_err_en; #endif static u32 orig_l2_err_disable; -#ifdef CONFIG_FSL_SOC_BOOKE -static u32 orig_hid1[2]; -#endif /************************ MC SYSFS parts ***********************************/ @@ -1231,14 +1228,6 @@ static struct platform_driver mpc85xx_mc_err_driver = { }, }; -#ifdef CONFIG_FSL_SOC_BOOKE -static void __init mpc85xx_mc_clear_rfxe(void *data) -{ - orig_hid1[smp_processor_id()] = mfspr(SPRN_HID1); - mtspr(SPRN_HID1, (orig_hid1[smp_processor_id()] & ~HID1_RFXE)); -} -#endif - static struct platform_driver * const drivers[] = { &mpc85xx_mc_err_driver, &mpc85xx_l2_err_driver, @@ -1269,42 +1258,13 @@ static int __init mpc85xx_mc_init(void) if (res) printk(KERN_WARNING EDAC_MOD_STR "drivers fail to register\n"); -#ifdef CONFIG_FSL_SOC_BOOKE - pvr = mfspr(SPRN_PVR); - - if ((PVR_VER(pvr) == PVR_VER_E500V1) || - (PVR_VER(pvr) == PVR_VER_E500V2)) { - /* - * need to clear HID1[RFXE] to disable machine check int - * so we can catch it - */ - if (edac_op_state == EDAC_OPSTATE_INT) - on_each_cpu(mpc85xx_mc_clear_rfxe, NULL, 0); - } -#endif - return 0; } module_init(mpc85xx_mc_init); -#ifdef CONFIG_FSL_SOC_BOOKE -static void __exit mpc85xx_mc_restore_hid1(void *data) -{ - mtspr(SPRN_HID1, orig_hid1[smp_processor_id()]); -} -#endif - static void __exit mpc85xx_mc_exit(void) { -#ifdef CONFIG_FSL_SOC_BOOKE - u32 pvr = mfspr(SPRN_PVR); - - if ((PVR_VER(pvr) == PVR_VER_E500V1) || - (PVR_VER(pvr) == PVR_VER_E500V2)) { - on_each_cpu(mpc85xx_mc_restore_hid1, NULL, 0); - } -#endif platform_unregister_drivers(drivers, ARRAY_SIZE(drivers)); } -- cgit v1.2.3 From 88857ebe7116b0f7702200628fa6b4d1297751a3 Mon Sep 17 00:00:00 2001 From: York Sun Date: Tue, 9 Aug 2016 14:55:39 -0700 Subject: EDAC, mpc85xx: Replace printk() with pr_* format Replace printk() with pr_err/pr_warn/pr_info macros. Signed-off-by: York Sun Cc: Johannes Thumshirn Cc: linux-edac Cc: oss@buserror.net Cc: stuart.yoder@nxp.com Link: http://lkml.kernel.org/r/1470779760-16483-3-git-send-email-york.sun@nxp.com [ Boris: unbreak strings for easier greppability. ] Signed-off-by: Borislav Petkov --- drivers/edac/mpc85xx_edac.c | 87 ++++++++++++++++++++------------------------- 1 file changed, 38 insertions(+), 49 deletions(-) diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index 39ee9267170b..73d809535eb3 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -157,18 +157,18 @@ static void mpc85xx_pci_check(struct edac_pci_ctl_info *pci) return; } - printk(KERN_ERR "PCI error(s) detected\n"); - printk(KERN_ERR "PCI/X ERR_DR register: %#08x\n", err_detect); + pr_err("PCI error(s) detected\n"); + pr_err("PCI/X ERR_DR register: %#08x\n", err_detect); - printk(KERN_ERR "PCI/X ERR_ATTRIB register: %#08x\n", + pr_err("PCI/X ERR_ATTRIB register: %#08x\n", in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ATTRIB)); - printk(KERN_ERR "PCI/X ERR_ADDR register: %#08x\n", + pr_err("PCI/X ERR_ADDR register: %#08x\n", in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_ADDR)); - printk(KERN_ERR "PCI/X ERR_EXT_ADDR register: %#08x\n", + pr_err("PCI/X ERR_EXT_ADDR register: %#08x\n", in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_EXT_ADDR)); - printk(KERN_ERR "PCI/X ERR_DL register: %#08x\n", + pr_err("PCI/X ERR_DL register: %#08x\n", in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DL)); - printk(KERN_ERR "PCI/X ERR_DH register: %#08x\n", + pr_err("PCI/X ERR_DH register: %#08x\n", in_be32(pdata->pci_vbase + MPC85XX_PCI_ERR_DH)); /* clear error bits */ @@ -297,8 +297,7 @@ static int mpc85xx_pci_err_probe(struct platform_device *op) res = of_address_to_resource(of_node, 0, &r); if (res) { - printk(KERN_ERR "%s: Unable to get resource for " - "PCI err regs\n", __func__); + pr_err("%s: Unable to get resource for PCI err regs\n", __func__); goto err; } @@ -307,15 +306,14 @@ static int mpc85xx_pci_err_probe(struct platform_device *op) if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r), pdata->name)) { - printk(KERN_ERR "%s: Error while requesting mem region\n", - __func__); + pr_err("%s: Error while requesting mem region\n", __func__); res = -EBUSY; goto err; } pdata->pci_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r)); if (!pdata->pci_vbase) { - printk(KERN_ERR "%s: Unable to setup PCI err regs\n", __func__); + pr_err("%s: Unable to setup PCI err regs\n", __func__); res = -ENOMEM; goto err; } @@ -359,15 +357,14 @@ static int mpc85xx_pci_err_probe(struct platform_device *op) IRQF_SHARED, "[EDAC] PCI err", pci); if (res < 0) { - printk(KERN_ERR - "%s: Unable to request irq %d for " - "MPC85xx PCI err\n", __func__, pdata->irq); + pr_err("%s: Unable to request irq %d for MPC85xx PCI err\n", + __func__, pdata->irq); irq_dispose_mapping(pdata->irq); res = -ENODEV; goto err2; } - printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for PCI Err\n", + pr_info(EDAC_MOD_STR " acquired irq %d for PCI Err\n", pdata->irq); } @@ -389,7 +386,7 @@ static int mpc85xx_pci_err_probe(struct platform_device *op) devres_remove_group(&op->dev, mpc85xx_pci_err_probe); edac_dbg(3, "success\n"); - printk(KERN_INFO EDAC_MOD_STR " PCI err registered\n"); + pr_info(EDAC_MOD_STR " PCI err registered\n"); return 0; @@ -532,17 +529,17 @@ static void mpc85xx_l2_check(struct edac_device_ctl_info *edac_dev) if (!(err_detect & L2_EDE_MASK)) return; - printk(KERN_ERR "ECC Error in CPU L2 cache\n"); - printk(KERN_ERR "L2 Error Detect Register: 0x%08x\n", err_detect); - printk(KERN_ERR "L2 Error Capture Data High Register: 0x%08x\n", + pr_err("ECC Error in CPU L2 cache\n"); + pr_err("L2 Error Detect Register: 0x%08x\n", err_detect); + pr_err("L2 Error Capture Data High Register: 0x%08x\n", in_be32(pdata->l2_vbase + MPC85XX_L2_CAPTDATAHI)); - printk(KERN_ERR "L2 Error Capture Data Lo Register: 0x%08x\n", + pr_err("L2 Error Capture Data Lo Register: 0x%08x\n", in_be32(pdata->l2_vbase + MPC85XX_L2_CAPTDATALO)); - printk(KERN_ERR "L2 Error Syndrome Register: 0x%08x\n", + pr_err("L2 Error Syndrome Register: 0x%08x\n", in_be32(pdata->l2_vbase + MPC85XX_L2_CAPTECC)); - printk(KERN_ERR "L2 Error Attributes Capture Register: 0x%08x\n", + pr_err("L2 Error Attributes Capture Register: 0x%08x\n", in_be32(pdata->l2_vbase + MPC85XX_L2_ERRATTR)); - printk(KERN_ERR "L2 Error Address Capture Register: 0x%08x\n", + pr_err("L2 Error Address Capture Register: 0x%08x\n", in_be32(pdata->l2_vbase + MPC85XX_L2_ERRADDR)); /* clear error detect register */ @@ -599,8 +596,7 @@ static int mpc85xx_l2_err_probe(struct platform_device *op) res = of_address_to_resource(op->dev.of_node, 0, &r); if (res) { - printk(KERN_ERR "%s: Unable to get resource for " - "L2 err regs\n", __func__); + pr_err("%s: Unable to get resource for L2 err regs\n", __func__); goto err; } @@ -609,15 +605,14 @@ static int mpc85xx_l2_err_probe(struct platform_device *op) if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r), pdata->name)) { - printk(KERN_ERR "%s: Error while requesting mem region\n", - __func__); + pr_err("%s: Error while requesting mem region\n", __func__); res = -EBUSY; goto err; } pdata->l2_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r)); if (!pdata->l2_vbase) { - printk(KERN_ERR "%s: Unable to setup L2 err regs\n", __func__); + pr_err("%s: Unable to setup L2 err regs\n", __func__); res = -ENOMEM; goto err; } @@ -649,16 +644,14 @@ static int mpc85xx_l2_err_probe(struct platform_device *op) mpc85xx_l2_isr, IRQF_SHARED, "[EDAC] L2 err", edac_dev); if (res < 0) { - printk(KERN_ERR - "%s: Unable to request irq %d for " - "MPC85xx L2 err\n", __func__, pdata->irq); + pr_err("%s: Unable to request irq %d for MPC85xx L2 err\n", + __func__, pdata->irq); irq_dispose_mapping(pdata->irq); res = -ENODEV; goto err2; } - printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for L2 Err\n", - pdata->irq); + pr_info(EDAC_MOD_STR " acquired irq %d for L2 Err\n", pdata->irq); edac_dev->op_state = OP_RUNNING_INTERRUPT; @@ -668,7 +661,7 @@ static int mpc85xx_l2_err_probe(struct platform_device *op) devres_remove_group(&op->dev, mpc85xx_l2_err_probe); edac_dbg(3, "success\n"); - printk(KERN_INFO EDAC_MOD_STR " L2 err registered\n"); + pr_info(EDAC_MOD_STR " L2 err registered\n"); return 0; @@ -1070,22 +1063,20 @@ static int mpc85xx_mc_err_probe(struct platform_device *op) res = of_address_to_resource(op->dev.of_node, 0, &r); if (res) { - printk(KERN_ERR "%s: Unable to get resource for MC err regs\n", - __func__); + pr_err("%s: Unable to get resource for MC err regs\n", __func__); goto err; } if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r), pdata->name)) { - printk(KERN_ERR "%s: Error while requesting mem region\n", - __func__); + pr_err("%s: Error while requesting mem region\n", __func__); res = -EBUSY; goto err; } pdata->mc_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r)); if (!pdata->mc_vbase) { - printk(KERN_ERR "%s: Unable to setup MC err regs\n", __func__); + pr_err("%s: Unable to setup MC err regs\n", __func__); res = -ENOMEM; goto err; } @@ -1093,7 +1084,7 @@ static int mpc85xx_mc_err_probe(struct platform_device *op) sdram_ctl = in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG); if (!(sdram_ctl & DSC_ECC_EN)) { /* no ECC */ - printk(KERN_WARNING "%s: No ECC DIMMs discovered\n", __func__); + pr_warn("%s: No ECC DIMMs discovered\n", __func__); res = -ENODEV; goto err; } @@ -1146,20 +1137,19 @@ static int mpc85xx_mc_err_probe(struct platform_device *op) IRQF_SHARED, "[EDAC] MC err", mci); if (res < 0) { - printk(KERN_ERR "%s: Unable to request irq %d for " - "MPC85xx DRAM ERR\n", __func__, pdata->irq); + pr_err("%s: Unable to request irq %d for MPC85xx DRAM ERR\n", + __func__, pdata->irq); irq_dispose_mapping(pdata->irq); res = -ENODEV; goto err2; } - printk(KERN_INFO EDAC_MOD_STR " acquired irq %d for MC\n", - pdata->irq); + pr_info(EDAC_MOD_STR " acquired irq %d for MC\n", pdata->irq); } devres_remove_group(&op->dev, mpc85xx_mc_err_probe); edac_dbg(3, "success\n"); - printk(KERN_INFO EDAC_MOD_STR " MC err registered\n"); + pr_info(EDAC_MOD_STR " MC err registered\n"); return 0; @@ -1241,8 +1231,7 @@ static int __init mpc85xx_mc_init(void) int res = 0; u32 __maybe_unused pvr = 0; - printk(KERN_INFO "Freescale(R) MPC85xx EDAC driver, " - "(C) 2006 Montavista Software\n"); + pr_info("Freescale(R) MPC85xx EDAC driver, (C) 2006 Montavista Software\n"); /* make sure error reporting method is sane */ switch (edac_op_state) { @@ -1256,7 +1245,7 @@ static int __init mpc85xx_mc_init(void) res = platform_register_drivers(drivers, ARRAY_SIZE(drivers)); if (res) - printk(KERN_WARNING EDAC_MOD_STR "drivers fail to register\n"); + pr_warn(EDAC_MOD_STR "drivers fail to register\n"); return 0; } -- cgit v1.2.3 From ea2eb9a8b6207ee40fdc346956686d8753aea944 Mon Sep 17 00:00:00 2001 From: York Sun Date: Thu, 11 Aug 2016 13:15:18 -0700 Subject: EDAC, fsl-ddr: Separate FSL DDR driver from MPC85xx The mpc85xx-compatible DDR controllers are used on ARM-based SoCs too. Carve out the DDR part from the mpc85xx EDAC driver in preparation to support both architectures. Signed-off-by: York Sun Cc: Johannes Thumshirn Cc: linux-edac Cc: oss@buserror.net Cc: stuart.yoder@nxp.com Link: http://lkml.kernel.org/r/1470946525-3410-1-git-send-email-york.sun@nxp.com Signed-off-by: Borislav Petkov --- drivers/edac/Makefile | 5 +- drivers/edac/fsl_ddr_edac.c | 592 ++++++++++++++++++++++++++++++++++++++++++++ drivers/edac/fsl_ddr_edac.h | 86 +++++++ drivers/edac/mpc85xx_edac.c | 556 +---------------------------------------- drivers/edac/mpc85xx_edac.h | 66 ----- 5 files changed, 683 insertions(+), 622 deletions(-) create mode 100644 drivers/edac/fsl_ddr_edac.c create mode 100644 drivers/edac/fsl_ddr_edac.h diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index f9e4a3e0e6e9..ee047a415722 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -50,7 +50,10 @@ amd64_edac_mod-$(CONFIG_EDAC_AMD64_ERROR_INJECTION) += amd64_edac_inj.o obj-$(CONFIG_EDAC_AMD64) += amd64_edac_mod.o obj-$(CONFIG_EDAC_PASEMI) += pasemi_edac.o -obj-$(CONFIG_EDAC_MPC85XX) += mpc85xx_edac.o + +mpc85xx_edac_mod-y := fsl_ddr_edac.o mpc85xx_edac.o +obj-$(CONFIG_EDAC_MPC85XX) += mpc85xx_edac_mod.o + obj-$(CONFIG_EDAC_MV64X60) += mv64x60_edac.o obj-$(CONFIG_EDAC_CELL) += cell_edac.o obj-$(CONFIG_EDAC_PPC4XX) += ppc4xx_edac.o diff --git a/drivers/edac/fsl_ddr_edac.c b/drivers/edac/fsl_ddr_edac.c new file mode 100644 index 000000000000..ca7636fbc799 --- /dev/null +++ b/drivers/edac/fsl_ddr_edac.c @@ -0,0 +1,592 @@ +/* + * Freescale Memory Controller kernel module + * + * Support Power-based SoCs including MPC85xx, MPC86xx, MPC83xx and + * ARM-based Layerscape SoCs including LS2xxx. Originally split + * out from mpc85xx_edac EDAC driver. + * + * Parts Copyrighted (c) 2013 by Freescale Semiconductor, Inc. + * + * Author: Dave Jiang + * + * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "edac_module.h" +#include "edac_core.h" +#include "fsl_ddr_edac.h" + +#define EDAC_MOD_STR "fsl_ddr_edac" + +static int edac_mc_idx; + +static u32 orig_ddr_err_disable; +static u32 orig_ddr_err_sbe; + +/************************ MC SYSFS parts ***********************************/ + +#define to_mci(k) container_of(k, struct mem_ctl_info, dev) + +static ssize_t mpc85xx_mc_inject_data_hi_show(struct device *dev, + struct device_attribute *mattr, + char *data) +{ + struct mem_ctl_info *mci = to_mci(dev); + struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + return sprintf(data, "0x%08x", + in_be32(pdata->mc_vbase + + MPC85XX_MC_DATA_ERR_INJECT_HI)); +} + +static ssize_t mpc85xx_mc_inject_data_lo_show(struct device *dev, + struct device_attribute *mattr, + char *data) +{ + struct mem_ctl_info *mci = to_mci(dev); + struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + return sprintf(data, "0x%08x", + in_be32(pdata->mc_vbase + + MPC85XX_MC_DATA_ERR_INJECT_LO)); +} + +static ssize_t mpc85xx_mc_inject_ctrl_show(struct device *dev, + struct device_attribute *mattr, + char *data) +{ + struct mem_ctl_info *mci = to_mci(dev); + struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + return sprintf(data, "0x%08x", + in_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT)); +} + +static ssize_t mpc85xx_mc_inject_data_hi_store(struct device *dev, + struct device_attribute *mattr, + const char *data, size_t count) +{ + struct mem_ctl_info *mci = to_mci(dev); + struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + if (isdigit(*data)) { + out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_HI, + simple_strtoul(data, NULL, 0)); + return count; + } + return 0; +} + +static ssize_t mpc85xx_mc_inject_data_lo_store(struct device *dev, + struct device_attribute *mattr, + const char *data, size_t count) +{ + struct mem_ctl_info *mci = to_mci(dev); + struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + if (isdigit(*data)) { + out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_LO, + simple_strtoul(data, NULL, 0)); + return count; + } + return 0; +} + +static ssize_t mpc85xx_mc_inject_ctrl_store(struct device *dev, + struct device_attribute *mattr, + const char *data, size_t count) +{ + struct mem_ctl_info *mci = to_mci(dev); + struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + if (isdigit(*data)) { + out_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT, + simple_strtoul(data, NULL, 0)); + return count; + } + return 0; +} + +DEVICE_ATTR(inject_data_hi, S_IRUGO | S_IWUSR, + mpc85xx_mc_inject_data_hi_show, mpc85xx_mc_inject_data_hi_store); +DEVICE_ATTR(inject_data_lo, S_IRUGO | S_IWUSR, + mpc85xx_mc_inject_data_lo_show, mpc85xx_mc_inject_data_lo_store); +DEVICE_ATTR(inject_ctrl, S_IRUGO | S_IWUSR, + mpc85xx_mc_inject_ctrl_show, mpc85xx_mc_inject_ctrl_store); + +static struct attribute *mpc85xx_dev_attrs[] = { + &dev_attr_inject_data_hi.attr, + &dev_attr_inject_data_lo.attr, + &dev_attr_inject_ctrl.attr, + NULL +}; + +ATTRIBUTE_GROUPS(mpc85xx_dev); + +/**************************** MC Err device ***************************/ + +/* + * Taken from table 8-55 in the MPC8641 User's Manual and/or 9-61 in the + * MPC8572 User's Manual. Each line represents a syndrome bit column as a + * 64-bit value, but split into an upper and lower 32-bit chunk. The labels + * below correspond to Freescale's manuals. + */ +static unsigned int ecc_table[16] = { + /* MSB LSB */ + /* [0:31] [32:63] */ + 0xf00fe11e, 0xc33c0ff7, /* Syndrome bit 7 */ + 0x00ff00ff, 0x00fff0ff, + 0x0f0f0f0f, 0x0f0fff00, + 0x11113333, 0x7777000f, + 0x22224444, 0x8888222f, + 0x44448888, 0xffff4441, + 0x8888ffff, 0x11118882, + 0xffff1111, 0x22221114, /* Syndrome bit 0 */ +}; + +/* + * Calculate the correct ECC value for a 64-bit value specified by high:low + */ +static u8 calculate_ecc(u32 high, u32 low) +{ + u32 mask_low; + u32 mask_high; + int bit_cnt; + u8 ecc = 0; + int i; + int j; + + for (i = 0; i < 8; i++) { + mask_high = ecc_table[i * 2]; + mask_low = ecc_table[i * 2 + 1]; + bit_cnt = 0; + + for (j = 0; j < 32; j++) { + if ((mask_high >> j) & 1) + bit_cnt ^= (high >> j) & 1; + if ((mask_low >> j) & 1) + bit_cnt ^= (low >> j) & 1; + } + + ecc |= bit_cnt << i; + } + + return ecc; +} + +/* + * Create the syndrome code which is generated if the data line specified by + * 'bit' failed. Eg generate an 8-bit codes seen in Table 8-55 in the MPC8641 + * User's Manual and 9-61 in the MPC8572 User's Manual. + */ +static u8 syndrome_from_bit(unsigned int bit) { + int i; + u8 syndrome = 0; + + /* + * Cycle through the upper or lower 32-bit portion of each value in + * ecc_table depending on if 'bit' is in the upper or lower half of + * 64-bit data. + */ + for (i = bit < 32; i < 16; i += 2) + syndrome |= ((ecc_table[i] >> (bit % 32)) & 1) << (i / 2); + + return syndrome; +} + +/* + * Decode data and ecc syndrome to determine what went wrong + * Note: This can only decode single-bit errors + */ +static void sbe_ecc_decode(u32 cap_high, u32 cap_low, u32 cap_ecc, + int *bad_data_bit, int *bad_ecc_bit) +{ + int i; + u8 syndrome; + + *bad_data_bit = -1; + *bad_ecc_bit = -1; + + /* + * Calculate the ECC of the captured data and XOR it with the captured + * ECC to find an ECC syndrome value we can search for + */ + syndrome = calculate_ecc(cap_high, cap_low) ^ cap_ecc; + + /* Check if a data line is stuck... */ + for (i = 0; i < 64; i++) { + if (syndrome == syndrome_from_bit(i)) { + *bad_data_bit = i; + return; + } + } + + /* If data is correct, check ECC bits for errors... */ + for (i = 0; i < 8; i++) { + if ((syndrome >> i) & 0x1) { + *bad_ecc_bit = i; + return; + } + } +} + +#define make64(high, low) (((u64)(high) << 32) | (low)) + +static void mpc85xx_mc_check(struct mem_ctl_info *mci) +{ + struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + struct csrow_info *csrow; + u32 bus_width; + u32 err_detect; + u32 syndrome; + u64 err_addr; + u32 pfn; + int row_index; + u32 cap_high; + u32 cap_low; + int bad_data_bit; + int bad_ecc_bit; + + err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT); + if (!err_detect) + return; + + mpc85xx_mc_printk(mci, KERN_ERR, "Err Detect Register: %#8.8x\n", + err_detect); + + /* no more processing if not ECC bit errors */ + if (!(err_detect & (DDR_EDE_SBE | DDR_EDE_MBE))) { + out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect); + return; + } + + syndrome = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ECC); + + /* Mask off appropriate bits of syndrome based on bus width */ + bus_width = (in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG) & + DSC_DBW_MASK) ? 32 : 64; + if (bus_width == 64) + syndrome &= 0xff; + else + syndrome &= 0xffff; + + err_addr = make64( + in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_EXT_ADDRESS), + in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ADDRESS)); + pfn = err_addr >> PAGE_SHIFT; + + for (row_index = 0; row_index < mci->nr_csrows; row_index++) { + csrow = mci->csrows[row_index]; + if ((pfn >= csrow->first_page) && (pfn <= csrow->last_page)) + break; + } + + cap_high = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_DATA_HI); + cap_low = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_DATA_LO); + + /* + * Analyze single-bit errors on 64-bit wide buses + * TODO: Add support for 32-bit wide buses + */ + if ((err_detect & DDR_EDE_SBE) && (bus_width == 64)) { + sbe_ecc_decode(cap_high, cap_low, syndrome, + &bad_data_bit, &bad_ecc_bit); + + if (bad_data_bit != -1) + mpc85xx_mc_printk(mci, KERN_ERR, + "Faulty Data bit: %d\n", bad_data_bit); + if (bad_ecc_bit != -1) + mpc85xx_mc_printk(mci, KERN_ERR, + "Faulty ECC bit: %d\n", bad_ecc_bit); + + mpc85xx_mc_printk(mci, KERN_ERR, + "Expected Data / ECC:\t%#8.8x_%08x / %#2.2x\n", + cap_high ^ (1 << (bad_data_bit - 32)), + cap_low ^ (1 << bad_data_bit), + syndrome ^ (1 << bad_ecc_bit)); + } + + mpc85xx_mc_printk(mci, KERN_ERR, + "Captured Data / ECC:\t%#8.8x_%08x / %#2.2x\n", + cap_high, cap_low, syndrome); + mpc85xx_mc_printk(mci, KERN_ERR, "Err addr: %#8.8llx\n", err_addr); + mpc85xx_mc_printk(mci, KERN_ERR, "PFN: %#8.8x\n", pfn); + + /* we are out of range */ + if (row_index == mci->nr_csrows) + mpc85xx_mc_printk(mci, KERN_ERR, "PFN out of range!\n"); + + if (err_detect & DDR_EDE_SBE) + edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, + pfn, err_addr & ~PAGE_MASK, syndrome, + row_index, 0, -1, + mci->ctl_name, ""); + + if (err_detect & DDR_EDE_MBE) + edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, + pfn, err_addr & ~PAGE_MASK, syndrome, + row_index, 0, -1, + mci->ctl_name, ""); + + out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect); +} + +static irqreturn_t mpc85xx_mc_isr(int irq, void *dev_id) +{ + struct mem_ctl_info *mci = dev_id; + struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + u32 err_detect; + + err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT); + if (!err_detect) + return IRQ_NONE; + + mpc85xx_mc_check(mci); + + return IRQ_HANDLED; +} + +static void mpc85xx_init_csrows(struct mem_ctl_info *mci) +{ + struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + struct csrow_info *csrow; + struct dimm_info *dimm; + u32 sdram_ctl; + u32 sdtype; + enum mem_type mtype; + u32 cs_bnds; + int index; + + sdram_ctl = in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG); + + sdtype = sdram_ctl & DSC_SDTYPE_MASK; + if (sdram_ctl & DSC_RD_EN) { + switch (sdtype) { + case DSC_SDTYPE_DDR: + mtype = MEM_RDDR; + break; + case DSC_SDTYPE_DDR2: + mtype = MEM_RDDR2; + break; + case DSC_SDTYPE_DDR3: + mtype = MEM_RDDR3; + break; + default: + mtype = MEM_UNKNOWN; + break; + } + } else { + switch (sdtype) { + case DSC_SDTYPE_DDR: + mtype = MEM_DDR; + break; + case DSC_SDTYPE_DDR2: + mtype = MEM_DDR2; + break; + case DSC_SDTYPE_DDR3: + mtype = MEM_DDR3; + break; + default: + mtype = MEM_UNKNOWN; + break; + } + } + + for (index = 0; index < mci->nr_csrows; index++) { + u32 start; + u32 end; + + csrow = mci->csrows[index]; + dimm = csrow->channels[0]->dimm; + + cs_bnds = in_be32(pdata->mc_vbase + MPC85XX_MC_CS_BNDS_0 + + (index * MPC85XX_MC_CS_BNDS_OFS)); + + start = (cs_bnds & 0xffff0000) >> 16; + end = (cs_bnds & 0x0000ffff); + + if (start == end) + continue; /* not populated */ + + start <<= (24 - PAGE_SHIFT); + end <<= (24 - PAGE_SHIFT); + end |= (1 << (24 - PAGE_SHIFT)) - 1; + + csrow->first_page = start; + csrow->last_page = end; + + dimm->nr_pages = end + 1 - start; + dimm->grain = 8; + dimm->mtype = mtype; + dimm->dtype = DEV_UNKNOWN; + if (sdram_ctl & DSC_X32_EN) + dimm->dtype = DEV_X32; + dimm->edac_mode = EDAC_SECDED; + } +} + +int mpc85xx_mc_err_probe(struct platform_device *op) +{ + struct mem_ctl_info *mci; + struct edac_mc_layer layers[2]; + struct mpc85xx_mc_pdata *pdata; + struct resource r; + u32 sdram_ctl; + int res; + + if (!devres_open_group(&op->dev, mpc85xx_mc_err_probe, GFP_KERNEL)) + return -ENOMEM; + + layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; + layers[0].size = 4; + layers[0].is_virt_csrow = true; + layers[1].type = EDAC_MC_LAYER_CHANNEL; + layers[1].size = 1; + layers[1].is_virt_csrow = false; + mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), layers, + sizeof(*pdata)); + if (!mci) { + devres_release_group(&op->dev, mpc85xx_mc_err_probe); + return -ENOMEM; + } + + pdata = mci->pvt_info; + pdata->name = "mpc85xx_mc_err"; + pdata->irq = NO_IRQ; + mci->pdev = &op->dev; + pdata->edac_idx = edac_mc_idx++; + dev_set_drvdata(mci->pdev, mci); + mci->ctl_name = pdata->name; + mci->dev_name = pdata->name; + + res = of_address_to_resource(op->dev.of_node, 0, &r); + if (res) { + pr_err("%s: Unable to get resource for MC err regs\n", + __func__); + goto err; + } + + if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r), + pdata->name)) { + pr_err("%s: Error while requesting mem region\n", + __func__); + res = -EBUSY; + goto err; + } + + pdata->mc_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r)); + if (!pdata->mc_vbase) { + pr_err("%s: Unable to setup MC err regs\n", __func__); + res = -ENOMEM; + goto err; + } + + sdram_ctl = in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG); + if (!(sdram_ctl & DSC_ECC_EN)) { + /* no ECC */ + pr_warn("%s: No ECC DIMMs discovered\n", __func__); + res = -ENODEV; + goto err; + } + + edac_dbg(3, "init mci\n"); + mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_RDDR2 | + MEM_FLAG_DDR | MEM_FLAG_DDR2; + mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; + mci->edac_cap = EDAC_FLAG_SECDED; + mci->mod_name = EDAC_MOD_STR; + + if (edac_op_state == EDAC_OPSTATE_POLL) + mci->edac_check = mpc85xx_mc_check; + + mci->ctl_page_to_phys = NULL; + + mci->scrub_mode = SCRUB_SW_SRC; + + mpc85xx_init_csrows(mci); + + /* store the original error disable bits */ + orig_ddr_err_disable = + in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE); + out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE, 0); + + /* clear all error bits */ + out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, ~0); + + if (edac_mc_add_mc_with_groups(mci, mpc85xx_dev_groups)) { + edac_dbg(3, "failed edac_mc_add_mc()\n"); + goto err; + } + + if (edac_op_state == EDAC_OPSTATE_INT) { + out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_INT_EN, + DDR_EIE_MBEE | DDR_EIE_SBEE); + + /* store the original error management threshold */ + orig_ddr_err_sbe = in_be32(pdata->mc_vbase + + MPC85XX_MC_ERR_SBE) & 0xff0000; + + /* set threshold to 1 error per interrupt */ + out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, 0x10000); + + /* register interrupts */ + pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); + res = devm_request_irq(&op->dev, pdata->irq, + mpc85xx_mc_isr, + IRQF_SHARED, + "[EDAC] MC err", mci); + if (res < 0) { + pr_err("%s: Unable to request irq %d for MPC85xx DRAM ERR\n", + __func__, pdata->irq); + irq_dispose_mapping(pdata->irq); + res = -ENODEV; + goto err2; + } + + pr_info(EDAC_MOD_STR " acquired irq %d for MC\n", + pdata->irq); + } + + devres_remove_group(&op->dev, mpc85xx_mc_err_probe); + edac_dbg(3, "success\n"); + pr_info(EDAC_MOD_STR " MC err registered\n"); + + return 0; + +err2: + edac_mc_del_mc(&op->dev); +err: + devres_release_group(&op->dev, mpc85xx_mc_err_probe); + edac_mc_free(mci); + return res; +} + +int mpc85xx_mc_err_remove(struct platform_device *op) +{ + struct mem_ctl_info *mci = dev_get_drvdata(&op->dev); + struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + + edac_dbg(0, "\n"); + + if (edac_op_state == EDAC_OPSTATE_INT) { + out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_INT_EN, 0); + irq_dispose_mapping(pdata->irq); + } + + out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE, + orig_ddr_err_disable); + out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, orig_ddr_err_sbe); + + edac_mc_del_mc(&op->dev); + edac_mc_free(mci); + return 0; +} diff --git a/drivers/edac/fsl_ddr_edac.h b/drivers/edac/fsl_ddr_edac.h new file mode 100644 index 000000000000..2f2c2b1890b9 --- /dev/null +++ b/drivers/edac/fsl_ddr_edac.h @@ -0,0 +1,86 @@ +/* + * Freescale Memory Controller kernel module + * + * Support Power-based SoCs including MPC85xx, MPC86xx, MPC83xx and + * ARM-based Layerscape SoCs including LS2xxx. Originally split + * out from mpc85xx_edac EDAC driver. + * + * Author: Dave Jiang + * + * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + * + */ +#ifndef _FSL_DDR_EDAC_H_ +#define _FSL_DDR_EDAC_H_ + +#define mpc85xx_mc_printk(mci, level, fmt, arg...) \ + edac_mc_chipset_printk(mci, level, "FSL_DDR", fmt, ##arg) + +/* + * DRAM error defines + */ + +/* DDR_SDRAM_CFG */ +#define MPC85XX_MC_DDR_SDRAM_CFG 0x0110 +#define MPC85XX_MC_CS_BNDS_0 0x0000 +#define MPC85XX_MC_CS_BNDS_1 0x0008 +#define MPC85XX_MC_CS_BNDS_2 0x0010 +#define MPC85XX_MC_CS_BNDS_3 0x0018 +#define MPC85XX_MC_CS_BNDS_OFS 0x0008 + +#define MPC85XX_MC_DATA_ERR_INJECT_HI 0x0e00 +#define MPC85XX_MC_DATA_ERR_INJECT_LO 0x0e04 +#define MPC85XX_MC_ECC_ERR_INJECT 0x0e08 +#define MPC85XX_MC_CAPTURE_DATA_HI 0x0e20 +#define MPC85XX_MC_CAPTURE_DATA_LO 0x0e24 +#define MPC85XX_MC_CAPTURE_ECC 0x0e28 +#define MPC85XX_MC_ERR_DETECT 0x0e40 +#define MPC85XX_MC_ERR_DISABLE 0x0e44 +#define MPC85XX_MC_ERR_INT_EN 0x0e48 +#define MPC85XX_MC_CAPTURE_ATRIBUTES 0x0e4c +#define MPC85XX_MC_CAPTURE_ADDRESS 0x0e50 +#define MPC85XX_MC_CAPTURE_EXT_ADDRESS 0x0e54 +#define MPC85XX_MC_ERR_SBE 0x0e58 + +#define DSC_MEM_EN 0x80000000 +#define DSC_ECC_EN 0x20000000 +#define DSC_RD_EN 0x10000000 +#define DSC_DBW_MASK 0x00180000 +#define DSC_DBW_32 0x00080000 +#define DSC_DBW_64 0x00000000 + +#define DSC_SDTYPE_MASK 0x07000000 + +#define DSC_SDTYPE_DDR 0x02000000 +#define DSC_SDTYPE_DDR2 0x03000000 +#define DSC_SDTYPE_DDR3 0x07000000 +#define DSC_X32_EN 0x00000020 + +/* Err_Int_En */ +#define DDR_EIE_MSEE 0x1 /* memory select */ +#define DDR_EIE_SBEE 0x4 /* single-bit ECC error */ +#define DDR_EIE_MBEE 0x8 /* multi-bit ECC error */ + +/* Err_Detect */ +#define DDR_EDE_MSE 0x1 /* memory select */ +#define DDR_EDE_SBE 0x4 /* single-bit ECC error */ +#define DDR_EDE_MBE 0x8 /* multi-bit ECC error */ +#define DDR_EDE_MME 0x80000000 /* multiple memory errors */ + +/* Err_Disable */ +#define DDR_EDI_MSED 0x1 /* memory select disable */ +#define DDR_EDI_SBED 0x4 /* single-bit ECC error disable */ +#define DDR_EDI_MBED 0x8 /* multi-bit ECC error disable */ + +struct mpc85xx_mc_pdata { + char *name; + int edac_idx; + void __iomem *mc_vbase; + int irq; +}; +int mpc85xx_mc_err_probe(struct platform_device *op); +int mpc85xx_mc_err_remove(struct platform_device *op); +#endif diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index 73d809535eb3..c548a80f1823 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -27,15 +27,12 @@ #include "edac_module.h" #include "edac_core.h" #include "mpc85xx_edac.h" +#include "fsl_ddr_edac.h" static int edac_dev_idx; #ifdef CONFIG_PCI static int edac_pci_idx; #endif -static int edac_mc_idx; - -static u32 orig_ddr_err_disable; -static u32 orig_ddr_err_sbe; /* * PCI Err defines @@ -47,100 +44,6 @@ static u32 orig_pci_err_en; static u32 orig_l2_err_disable; -/************************ MC SYSFS parts ***********************************/ - -#define to_mci(k) container_of(k, struct mem_ctl_info, dev) - -static ssize_t mpc85xx_mc_inject_data_hi_show(struct device *dev, - struct device_attribute *mattr, - char *data) -{ - struct mem_ctl_info *mci = to_mci(dev); - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; - return sprintf(data, "0x%08x", - in_be32(pdata->mc_vbase + - MPC85XX_MC_DATA_ERR_INJECT_HI)); -} - -static ssize_t mpc85xx_mc_inject_data_lo_show(struct device *dev, - struct device_attribute *mattr, - char *data) -{ - struct mem_ctl_info *mci = to_mci(dev); - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; - return sprintf(data, "0x%08x", - in_be32(pdata->mc_vbase + - MPC85XX_MC_DATA_ERR_INJECT_LO)); -} - -static ssize_t mpc85xx_mc_inject_ctrl_show(struct device *dev, - struct device_attribute *mattr, - char *data) -{ - struct mem_ctl_info *mci = to_mci(dev); - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; - return sprintf(data, "0x%08x", - in_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT)); -} - -static ssize_t mpc85xx_mc_inject_data_hi_store(struct device *dev, - struct device_attribute *mattr, - const char *data, size_t count) -{ - struct mem_ctl_info *mci = to_mci(dev); - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; - if (isdigit(*data)) { - out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_HI, - simple_strtoul(data, NULL, 0)); - return count; - } - return 0; -} - -static ssize_t mpc85xx_mc_inject_data_lo_store(struct device *dev, - struct device_attribute *mattr, - const char *data, size_t count) -{ - struct mem_ctl_info *mci = to_mci(dev); - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; - if (isdigit(*data)) { - out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_LO, - simple_strtoul(data, NULL, 0)); - return count; - } - return 0; -} - -static ssize_t mpc85xx_mc_inject_ctrl_store(struct device *dev, - struct device_attribute *mattr, - const char *data, size_t count) -{ - struct mem_ctl_info *mci = to_mci(dev); - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; - if (isdigit(*data)) { - out_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT, - simple_strtoul(data, NULL, 0)); - return count; - } - return 0; -} - -DEVICE_ATTR(inject_data_hi, S_IRUGO | S_IWUSR, - mpc85xx_mc_inject_data_hi_show, mpc85xx_mc_inject_data_hi_store); -DEVICE_ATTR(inject_data_lo, S_IRUGO | S_IWUSR, - mpc85xx_mc_inject_data_lo_show, mpc85xx_mc_inject_data_lo_store); -DEVICE_ATTR(inject_ctrl, S_IRUGO | S_IWUSR, - mpc85xx_mc_inject_ctrl_show, mpc85xx_mc_inject_ctrl_store); - -static struct attribute *mpc85xx_dev_attrs[] = { - &dev_attr_inject_data_hi.attr, - &dev_attr_inject_data_lo.attr, - &dev_attr_inject_ctrl.attr, - NULL -}; - -ATTRIBUTE_GROUPS(mpc85xx_dev); - /**************************** PCI Err device ***************************/ #ifdef CONFIG_PCI @@ -725,463 +628,6 @@ static struct platform_driver mpc85xx_l2_err_driver = { }, }; -/**************************** MC Err device ***************************/ - -/* - * Taken from table 8-55 in the MPC8641 User's Manual and/or 9-61 in the - * MPC8572 User's Manual. Each line represents a syndrome bit column as a - * 64-bit value, but split into an upper and lower 32-bit chunk. The labels - * below correspond to Freescale's manuals. - */ -static unsigned int ecc_table[16] = { - /* MSB LSB */ - /* [0:31] [32:63] */ - 0xf00fe11e, 0xc33c0ff7, /* Syndrome bit 7 */ - 0x00ff00ff, 0x00fff0ff, - 0x0f0f0f0f, 0x0f0fff00, - 0x11113333, 0x7777000f, - 0x22224444, 0x8888222f, - 0x44448888, 0xffff4441, - 0x8888ffff, 0x11118882, - 0xffff1111, 0x22221114, /* Syndrome bit 0 */ -}; - -/* - * Calculate the correct ECC value for a 64-bit value specified by high:low - */ -static u8 calculate_ecc(u32 high, u32 low) -{ - u32 mask_low; - u32 mask_high; - int bit_cnt; - u8 ecc = 0; - int i; - int j; - - for (i = 0; i < 8; i++) { - mask_high = ecc_table[i * 2]; - mask_low = ecc_table[i * 2 + 1]; - bit_cnt = 0; - - for (j = 0; j < 32; j++) { - if ((mask_high >> j) & 1) - bit_cnt ^= (high >> j) & 1; - if ((mask_low >> j) & 1) - bit_cnt ^= (low >> j) & 1; - } - - ecc |= bit_cnt << i; - } - - return ecc; -} - -/* - * Create the syndrome code which is generated if the data line specified by - * 'bit' failed. Eg generate an 8-bit codes seen in Table 8-55 in the MPC8641 - * User's Manual and 9-61 in the MPC8572 User's Manual. - */ -static u8 syndrome_from_bit(unsigned int bit) { - int i; - u8 syndrome = 0; - - /* - * Cycle through the upper or lower 32-bit portion of each value in - * ecc_table depending on if 'bit' is in the upper or lower half of - * 64-bit data. - */ - for (i = bit < 32; i < 16; i += 2) - syndrome |= ((ecc_table[i] >> (bit % 32)) & 1) << (i / 2); - - return syndrome; -} - -/* - * Decode data and ecc syndrome to determine what went wrong - * Note: This can only decode single-bit errors - */ -static void sbe_ecc_decode(u32 cap_high, u32 cap_low, u32 cap_ecc, - int *bad_data_bit, int *bad_ecc_bit) -{ - int i; - u8 syndrome; - - *bad_data_bit = -1; - *bad_ecc_bit = -1; - - /* - * Calculate the ECC of the captured data and XOR it with the captured - * ECC to find an ECC syndrome value we can search for - */ - syndrome = calculate_ecc(cap_high, cap_low) ^ cap_ecc; - - /* Check if a data line is stuck... */ - for (i = 0; i < 64; i++) { - if (syndrome == syndrome_from_bit(i)) { - *bad_data_bit = i; - return; - } - } - - /* If data is correct, check ECC bits for errors... */ - for (i = 0; i < 8; i++) { - if ((syndrome >> i) & 0x1) { - *bad_ecc_bit = i; - return; - } - } -} - -#define make64(high, low) (((u64)(high) << 32) | (low)) - -static void mpc85xx_mc_check(struct mem_ctl_info *mci) -{ - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; - struct csrow_info *csrow; - u32 bus_width; - u32 err_detect; - u32 syndrome; - u64 err_addr; - u32 pfn; - int row_index; - u32 cap_high; - u32 cap_low; - int bad_data_bit; - int bad_ecc_bit; - - err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT); - if (!err_detect) - return; - - mpc85xx_mc_printk(mci, KERN_ERR, "Err Detect Register: %#8.8x\n", - err_detect); - - /* no more processing if not ECC bit errors */ - if (!(err_detect & (DDR_EDE_SBE | DDR_EDE_MBE))) { - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect); - return; - } - - syndrome = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ECC); - - /* Mask off appropriate bits of syndrome based on bus width */ - bus_width = (in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG) & - DSC_DBW_MASK) ? 32 : 64; - if (bus_width == 64) - syndrome &= 0xff; - else - syndrome &= 0xffff; - - err_addr = make64( - in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_EXT_ADDRESS), - in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ADDRESS)); - pfn = err_addr >> PAGE_SHIFT; - - for (row_index = 0; row_index < mci->nr_csrows; row_index++) { - csrow = mci->csrows[row_index]; - if ((pfn >= csrow->first_page) && (pfn <= csrow->last_page)) - break; - } - - cap_high = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_DATA_HI); - cap_low = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_DATA_LO); - - /* - * Analyze single-bit errors on 64-bit wide buses - * TODO: Add support for 32-bit wide buses - */ - if ((err_detect & DDR_EDE_SBE) && (bus_width == 64)) { - sbe_ecc_decode(cap_high, cap_low, syndrome, - &bad_data_bit, &bad_ecc_bit); - - if (bad_data_bit != -1) - mpc85xx_mc_printk(mci, KERN_ERR, - "Faulty Data bit: %d\n", bad_data_bit); - if (bad_ecc_bit != -1) - mpc85xx_mc_printk(mci, KERN_ERR, - "Faulty ECC bit: %d\n", bad_ecc_bit); - - mpc85xx_mc_printk(mci, KERN_ERR, - "Expected Data / ECC:\t%#8.8x_%08x / %#2.2x\n", - cap_high ^ (1 << (bad_data_bit - 32)), - cap_low ^ (1 << bad_data_bit), - syndrome ^ (1 << bad_ecc_bit)); - } - - mpc85xx_mc_printk(mci, KERN_ERR, - "Captured Data / ECC:\t%#8.8x_%08x / %#2.2x\n", - cap_high, cap_low, syndrome); - mpc85xx_mc_printk(mci, KERN_ERR, "Err addr: %#8.8llx\n", err_addr); - mpc85xx_mc_printk(mci, KERN_ERR, "PFN: %#8.8x\n", pfn); - - /* we are out of range */ - if (row_index == mci->nr_csrows) - mpc85xx_mc_printk(mci, KERN_ERR, "PFN out of range!\n"); - - if (err_detect & DDR_EDE_SBE) - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, - pfn, err_addr & ~PAGE_MASK, syndrome, - row_index, 0, -1, - mci->ctl_name, ""); - - if (err_detect & DDR_EDE_MBE) - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, - pfn, err_addr & ~PAGE_MASK, syndrome, - row_index, 0, -1, - mci->ctl_name, ""); - - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect); -} - -static irqreturn_t mpc85xx_mc_isr(int irq, void *dev_id) -{ - struct mem_ctl_info *mci = dev_id; - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; - u32 err_detect; - - err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT); - if (!err_detect) - return IRQ_NONE; - - mpc85xx_mc_check(mci); - - return IRQ_HANDLED; -} - -static void mpc85xx_init_csrows(struct mem_ctl_info *mci) -{ - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; - struct csrow_info *csrow; - struct dimm_info *dimm; - u32 sdram_ctl; - u32 sdtype; - enum mem_type mtype; - u32 cs_bnds; - int index; - - sdram_ctl = in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG); - - sdtype = sdram_ctl & DSC_SDTYPE_MASK; - if (sdram_ctl & DSC_RD_EN) { - switch (sdtype) { - case DSC_SDTYPE_DDR: - mtype = MEM_RDDR; - break; - case DSC_SDTYPE_DDR2: - mtype = MEM_RDDR2; - break; - case DSC_SDTYPE_DDR3: - mtype = MEM_RDDR3; - break; - default: - mtype = MEM_UNKNOWN; - break; - } - } else { - switch (sdtype) { - case DSC_SDTYPE_DDR: - mtype = MEM_DDR; - break; - case DSC_SDTYPE_DDR2: - mtype = MEM_DDR2; - break; - case DSC_SDTYPE_DDR3: - mtype = MEM_DDR3; - break; - default: - mtype = MEM_UNKNOWN; - break; - } - } - - for (index = 0; index < mci->nr_csrows; index++) { - u32 start; - u32 end; - - csrow = mci->csrows[index]; - dimm = csrow->channels[0]->dimm; - - cs_bnds = in_be32(pdata->mc_vbase + MPC85XX_MC_CS_BNDS_0 + - (index * MPC85XX_MC_CS_BNDS_OFS)); - - start = (cs_bnds & 0xffff0000) >> 16; - end = (cs_bnds & 0x0000ffff); - - if (start == end) - continue; /* not populated */ - - start <<= (24 - PAGE_SHIFT); - end <<= (24 - PAGE_SHIFT); - end |= (1 << (24 - PAGE_SHIFT)) - 1; - - csrow->first_page = start; - csrow->last_page = end; - - dimm->nr_pages = end + 1 - start; - dimm->grain = 8; - dimm->mtype = mtype; - dimm->dtype = DEV_UNKNOWN; - if (sdram_ctl & DSC_X32_EN) - dimm->dtype = DEV_X32; - dimm->edac_mode = EDAC_SECDED; - } -} - -static int mpc85xx_mc_err_probe(struct platform_device *op) -{ - struct mem_ctl_info *mci; - struct edac_mc_layer layers[2]; - struct mpc85xx_mc_pdata *pdata; - struct resource r; - u32 sdram_ctl; - int res; - - if (!devres_open_group(&op->dev, mpc85xx_mc_err_probe, GFP_KERNEL)) - return -ENOMEM; - - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = 4; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = 1; - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), layers, - sizeof(*pdata)); - if (!mci) { - devres_release_group(&op->dev, mpc85xx_mc_err_probe); - return -ENOMEM; - } - - pdata = mci->pvt_info; - pdata->name = "mpc85xx_mc_err"; - pdata->irq = NO_IRQ; - mci->pdev = &op->dev; - pdata->edac_idx = edac_mc_idx++; - dev_set_drvdata(mci->pdev, mci); - mci->ctl_name = pdata->name; - mci->dev_name = pdata->name; - - res = of_address_to_resource(op->dev.of_node, 0, &r); - if (res) { - pr_err("%s: Unable to get resource for MC err regs\n", __func__); - goto err; - } - - if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r), - pdata->name)) { - pr_err("%s: Error while requesting mem region\n", __func__); - res = -EBUSY; - goto err; - } - - pdata->mc_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r)); - if (!pdata->mc_vbase) { - pr_err("%s: Unable to setup MC err regs\n", __func__); - res = -ENOMEM; - goto err; - } - - sdram_ctl = in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG); - if (!(sdram_ctl & DSC_ECC_EN)) { - /* no ECC */ - pr_warn("%s: No ECC DIMMs discovered\n", __func__); - res = -ENODEV; - goto err; - } - - edac_dbg(3, "init mci\n"); - mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_RDDR2 | - MEM_FLAG_DDR | MEM_FLAG_DDR2; - mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; - mci->edac_cap = EDAC_FLAG_SECDED; - mci->mod_name = EDAC_MOD_STR; - mci->mod_ver = MPC85XX_REVISION; - - if (edac_op_state == EDAC_OPSTATE_POLL) - mci->edac_check = mpc85xx_mc_check; - - mci->ctl_page_to_phys = NULL; - - mci->scrub_mode = SCRUB_SW_SRC; - - mpc85xx_init_csrows(mci); - - /* store the original error disable bits */ - orig_ddr_err_disable = - in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE); - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE, 0); - - /* clear all error bits */ - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, ~0); - - if (edac_mc_add_mc_with_groups(mci, mpc85xx_dev_groups)) { - edac_dbg(3, "failed edac_mc_add_mc()\n"); - goto err; - } - - if (edac_op_state == EDAC_OPSTATE_INT) { - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_INT_EN, - DDR_EIE_MBEE | DDR_EIE_SBEE); - - /* store the original error management threshold */ - orig_ddr_err_sbe = in_be32(pdata->mc_vbase + - MPC85XX_MC_ERR_SBE) & 0xff0000; - - /* set threshold to 1 error per interrupt */ - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, 0x10000); - - /* register interrupts */ - pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); - res = devm_request_irq(&op->dev, pdata->irq, - mpc85xx_mc_isr, - IRQF_SHARED, - "[EDAC] MC err", mci); - if (res < 0) { - pr_err("%s: Unable to request irq %d for MPC85xx DRAM ERR\n", - __func__, pdata->irq); - irq_dispose_mapping(pdata->irq); - res = -ENODEV; - goto err2; - } - - pr_info(EDAC_MOD_STR " acquired irq %d for MC\n", pdata->irq); - } - - devres_remove_group(&op->dev, mpc85xx_mc_err_probe); - edac_dbg(3, "success\n"); - pr_info(EDAC_MOD_STR " MC err registered\n"); - - return 0; - -err2: - edac_mc_del_mc(&op->dev); -err: - devres_release_group(&op->dev, mpc85xx_mc_err_probe); - edac_mc_free(mci); - return res; -} - -static int mpc85xx_mc_err_remove(struct platform_device *op) -{ - struct mem_ctl_info *mci = dev_get_drvdata(&op->dev); - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; - - edac_dbg(0, "\n"); - - if (edac_op_state == EDAC_OPSTATE_INT) { - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_INT_EN, 0); - irq_dispose_mapping(pdata->irq); - } - - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE, - orig_ddr_err_disable); - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, orig_ddr_err_sbe); - - edac_mc_del_mc(&op->dev); - edac_mc_free(mci); - return 0; -} - static const struct of_device_id mpc85xx_mc_err_of_match[] = { /* deprecate the fsl,85.. forms in the future, 2.6.30? */ { .compatible = "fsl,8540-memory-controller", }, 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 @@ #define mpc85xx_printk(level, fmt, arg...) \ edac_printk(level, "MPC85xx", fmt, ##arg) -#define mpc85xx_mc_printk(mci, level, fmt, arg...) \ - edac_mc_chipset_printk(mci, level, "MPC85xx", fmt, ##arg) - -/* - * DRAM error defines - */ - -/* DDR_SDRAM_CFG */ -#define MPC85XX_MC_DDR_SDRAM_CFG 0x0110 -#define MPC85XX_MC_CS_BNDS_0 0x0000 -#define MPC85XX_MC_CS_BNDS_1 0x0008 -#define MPC85XX_MC_CS_BNDS_2 0x0010 -#define MPC85XX_MC_CS_BNDS_3 0x0018 -#define MPC85XX_MC_CS_BNDS_OFS 0x0008 - -#define MPC85XX_MC_DATA_ERR_INJECT_HI 0x0e00 -#define MPC85XX_MC_DATA_ERR_INJECT_LO 0x0e04 -#define MPC85XX_MC_ECC_ERR_INJECT 0x0e08 -#define MPC85XX_MC_CAPTURE_DATA_HI 0x0e20 -#define MPC85XX_MC_CAPTURE_DATA_LO 0x0e24 -#define MPC85XX_MC_CAPTURE_ECC 0x0e28 -#define MPC85XX_MC_ERR_DETECT 0x0e40 -#define MPC85XX_MC_ERR_DISABLE 0x0e44 -#define MPC85XX_MC_ERR_INT_EN 0x0e48 -#define MPC85XX_MC_CAPTURE_ATRIBUTES 0x0e4c -#define MPC85XX_MC_CAPTURE_ADDRESS 0x0e50 -#define MPC85XX_MC_CAPTURE_EXT_ADDRESS 0x0e54 -#define MPC85XX_MC_ERR_SBE 0x0e58 - -#define DSC_MEM_EN 0x80000000 -#define DSC_ECC_EN 0x20000000 -#define DSC_RD_EN 0x10000000 -#define DSC_DBW_MASK 0x00180000 -#define DSC_DBW_32 0x00080000 -#define DSC_DBW_64 0x00000000 - -#define DSC_SDTYPE_MASK 0x07000000 - -#define DSC_SDTYPE_DDR 0x02000000 -#define DSC_SDTYPE_DDR2 0x03000000 -#define DSC_SDTYPE_DDR3 0x07000000 -#define DSC_X32_EN 0x00000020 - -/* Err_Int_En */ -#define DDR_EIE_MSEE 0x1 /* memory select */ -#define DDR_EIE_SBEE 0x4 /* single-bit ECC error */ -#define DDR_EIE_MBEE 0x8 /* multi-bit ECC error */ - -/* Err_Detect */ -#define DDR_EDE_MSE 0x1 /* memory select */ -#define DDR_EDE_SBE 0x4 /* single-bit ECC error */ -#define DDR_EDE_MBE 0x8 /* multi-bit ECC error */ -#define DDR_EDE_MME 0x80000000 /* multiple memory errors */ - -/* Err_Disable */ -#define DDR_EDI_MSED 0x1 /* memory select disable */ -#define DDR_EDI_SBED 0x4 /* single-bit ECC error disable */ -#define DDR_EDI_MBED 0x8 /* multi-bit ECC error disable */ - /* * L2 Err defines */ @@ -149,13 +90,6 @@ #define MPC85XX_PCIE_ERR_CAP_R2 0x0030 #define MPC85XX_PCIE_ERR_CAP_R3 0x0034 -struct mpc85xx_mc_pdata { - char *name; - int edac_idx; - void __iomem *mc_vbase; - int irq; -}; - struct mpc85xx_l2_pdata { char *name; int edac_idx; -- cgit v1.2.3 From d43a9fb202bc86a6f5a2bb44b06cf9fd5581080b Mon Sep 17 00:00:00 2001 From: York Sun Date: Tue, 9 Aug 2016 14:55:41 -0700 Subject: EDAC, fsl_ddr: Rename macros and names Use FSL-specific prefix for macros, variables and functions. Signed-off-by: York Sun Cc: Johannes Thumshirn Cc: linux-edac Cc: oss@buserror.net Cc: stuart.yoder@nxp.com Link: http://lkml.kernel.org/r/1470779760-16483-5-git-send-email-york.sun@nxp.com Signed-off-by: Borislav Petkov --- drivers/edac/fsl_ddr_edac.c | 166 ++++++++++++++++++++++---------------------- drivers/edac/fsl_ddr_edac.h | 43 ++++++------ drivers/edac/mpc85xx_edac.c | 4 +- 3 files changed, 105 insertions(+), 108 deletions(-) diff --git a/drivers/edac/fsl_ddr_edac.c b/drivers/edac/fsl_ddr_edac.c index ca7636fbc799..26758337e23e 100644 --- a/drivers/edac/fsl_ddr_edac.c +++ b/drivers/edac/fsl_ddr_edac.c @@ -42,74 +42,74 @@ static u32 orig_ddr_err_sbe; #define to_mci(k) container_of(k, struct mem_ctl_info, dev) -static ssize_t mpc85xx_mc_inject_data_hi_show(struct device *dev, - struct device_attribute *mattr, - char *data) +static ssize_t fsl_mc_inject_data_hi_show(struct device *dev, + struct device_attribute *mattr, + char *data) { struct mem_ctl_info *mci = to_mci(dev); - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + struct fsl_mc_pdata *pdata = mci->pvt_info; return sprintf(data, "0x%08x", in_be32(pdata->mc_vbase + - MPC85XX_MC_DATA_ERR_INJECT_HI)); + FSL_MC_DATA_ERR_INJECT_HI)); } -static ssize_t mpc85xx_mc_inject_data_lo_show(struct device *dev, - struct device_attribute *mattr, +static ssize_t fsl_mc_inject_data_lo_show(struct device *dev, + struct device_attribute *mattr, char *data) { struct mem_ctl_info *mci = to_mci(dev); - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + struct fsl_mc_pdata *pdata = mci->pvt_info; return sprintf(data, "0x%08x", in_be32(pdata->mc_vbase + - MPC85XX_MC_DATA_ERR_INJECT_LO)); + FSL_MC_DATA_ERR_INJECT_LO)); } -static ssize_t mpc85xx_mc_inject_ctrl_show(struct device *dev, - struct device_attribute *mattr, +static ssize_t fsl_mc_inject_ctrl_show(struct device *dev, + struct device_attribute *mattr, char *data) { struct mem_ctl_info *mci = to_mci(dev); - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + struct fsl_mc_pdata *pdata = mci->pvt_info; return sprintf(data, "0x%08x", - in_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT)); + in_be32(pdata->mc_vbase + FSL_MC_ECC_ERR_INJECT)); } -static ssize_t mpc85xx_mc_inject_data_hi_store(struct device *dev, - struct device_attribute *mattr, +static ssize_t fsl_mc_inject_data_hi_store(struct device *dev, + struct device_attribute *mattr, const char *data, size_t count) { struct mem_ctl_info *mci = to_mci(dev); - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + struct fsl_mc_pdata *pdata = mci->pvt_info; if (isdigit(*data)) { - out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_HI, + out_be32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_HI, simple_strtoul(data, NULL, 0)); return count; } return 0; } -static ssize_t mpc85xx_mc_inject_data_lo_store(struct device *dev, - struct device_attribute *mattr, +static ssize_t fsl_mc_inject_data_lo_store(struct device *dev, + struct device_attribute *mattr, const char *data, size_t count) { struct mem_ctl_info *mci = to_mci(dev); - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + struct fsl_mc_pdata *pdata = mci->pvt_info; if (isdigit(*data)) { - out_be32(pdata->mc_vbase + MPC85XX_MC_DATA_ERR_INJECT_LO, + out_be32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_LO, simple_strtoul(data, NULL, 0)); return count; } return 0; } -static ssize_t mpc85xx_mc_inject_ctrl_store(struct device *dev, - struct device_attribute *mattr, +static ssize_t fsl_mc_inject_ctrl_store(struct device *dev, + struct device_attribute *mattr, const char *data, size_t count) { struct mem_ctl_info *mci = to_mci(dev); - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + struct fsl_mc_pdata *pdata = mci->pvt_info; if (isdigit(*data)) { - out_be32(pdata->mc_vbase + MPC85XX_MC_ECC_ERR_INJECT, + out_be32(pdata->mc_vbase + FSL_MC_ECC_ERR_INJECT, simple_strtoul(data, NULL, 0)); return count; } @@ -117,20 +117,20 @@ static ssize_t mpc85xx_mc_inject_ctrl_store(struct device *dev, } DEVICE_ATTR(inject_data_hi, S_IRUGO | S_IWUSR, - mpc85xx_mc_inject_data_hi_show, mpc85xx_mc_inject_data_hi_store); + fsl_mc_inject_data_hi_show, fsl_mc_inject_data_hi_store); DEVICE_ATTR(inject_data_lo, S_IRUGO | S_IWUSR, - mpc85xx_mc_inject_data_lo_show, mpc85xx_mc_inject_data_lo_store); + fsl_mc_inject_data_lo_show, fsl_mc_inject_data_lo_store); DEVICE_ATTR(inject_ctrl, S_IRUGO | S_IWUSR, - mpc85xx_mc_inject_ctrl_show, mpc85xx_mc_inject_ctrl_store); + fsl_mc_inject_ctrl_show, fsl_mc_inject_ctrl_store); -static struct attribute *mpc85xx_dev_attrs[] = { +static struct attribute *fsl_ddr_dev_attrs[] = { &dev_attr_inject_data_hi.attr, &dev_attr_inject_data_lo.attr, &dev_attr_inject_ctrl.attr, NULL }; -ATTRIBUTE_GROUPS(mpc85xx_dev); +ATTRIBUTE_GROUPS(fsl_ddr_dev); /**************************** MC Err device ***************************/ @@ -241,9 +241,9 @@ static void sbe_ecc_decode(u32 cap_high, u32 cap_low, u32 cap_ecc, #define make64(high, low) (((u64)(high) << 32) | (low)) -static void mpc85xx_mc_check(struct mem_ctl_info *mci) +static void fsl_mc_check(struct mem_ctl_info *mci) { - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + struct fsl_mc_pdata *pdata = mci->pvt_info; struct csrow_info *csrow; u32 bus_width; u32 err_detect; @@ -256,23 +256,23 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci) int bad_data_bit; int bad_ecc_bit; - err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT); + err_detect = in_be32(pdata->mc_vbase + FSL_MC_ERR_DETECT); if (!err_detect) return; - mpc85xx_mc_printk(mci, KERN_ERR, "Err Detect Register: %#8.8x\n", - err_detect); + fsl_mc_printk(mci, KERN_ERR, "Err Detect Register: %#8.8x\n", + err_detect); /* no more processing if not ECC bit errors */ if (!(err_detect & (DDR_EDE_SBE | DDR_EDE_MBE))) { - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect); + out_be32(pdata->mc_vbase + FSL_MC_ERR_DETECT, err_detect); return; } - syndrome = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ECC); + syndrome = in_be32(pdata->mc_vbase + FSL_MC_CAPTURE_ECC); /* Mask off appropriate bits of syndrome based on bus width */ - bus_width = (in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG) & + bus_width = (in_be32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG) & DSC_DBW_MASK) ? 32 : 64; if (bus_width == 64) syndrome &= 0xff; @@ -280,8 +280,8 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci) syndrome &= 0xffff; err_addr = make64( - in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_EXT_ADDRESS), - in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_ADDRESS)); + in_be32(pdata->mc_vbase + FSL_MC_CAPTURE_EXT_ADDRESS), + in_be32(pdata->mc_vbase + FSL_MC_CAPTURE_ADDRESS)); pfn = err_addr >> PAGE_SHIFT; for (row_index = 0; row_index < mci->nr_csrows; row_index++) { @@ -290,8 +290,8 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci) break; } - cap_high = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_DATA_HI); - cap_low = in_be32(pdata->mc_vbase + MPC85XX_MC_CAPTURE_DATA_LO); + cap_high = in_be32(pdata->mc_vbase + FSL_MC_CAPTURE_DATA_HI); + cap_low = in_be32(pdata->mc_vbase + FSL_MC_CAPTURE_DATA_LO); /* * Analyze single-bit errors on 64-bit wide buses @@ -302,28 +302,28 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci) &bad_data_bit, &bad_ecc_bit); if (bad_data_bit != -1) - mpc85xx_mc_printk(mci, KERN_ERR, + fsl_mc_printk(mci, KERN_ERR, "Faulty Data bit: %d\n", bad_data_bit); if (bad_ecc_bit != -1) - mpc85xx_mc_printk(mci, KERN_ERR, + fsl_mc_printk(mci, KERN_ERR, "Faulty ECC bit: %d\n", bad_ecc_bit); - mpc85xx_mc_printk(mci, KERN_ERR, + fsl_mc_printk(mci, KERN_ERR, "Expected Data / ECC:\t%#8.8x_%08x / %#2.2x\n", cap_high ^ (1 << (bad_data_bit - 32)), cap_low ^ (1 << bad_data_bit), syndrome ^ (1 << bad_ecc_bit)); } - mpc85xx_mc_printk(mci, KERN_ERR, + fsl_mc_printk(mci, KERN_ERR, "Captured Data / ECC:\t%#8.8x_%08x / %#2.2x\n", cap_high, cap_low, syndrome); - mpc85xx_mc_printk(mci, KERN_ERR, "Err addr: %#8.8llx\n", err_addr); - mpc85xx_mc_printk(mci, KERN_ERR, "PFN: %#8.8x\n", pfn); + fsl_mc_printk(mci, KERN_ERR, "Err addr: %#8.8llx\n", err_addr); + fsl_mc_printk(mci, KERN_ERR, "PFN: %#8.8x\n", pfn); /* we are out of range */ if (row_index == mci->nr_csrows) - mpc85xx_mc_printk(mci, KERN_ERR, "PFN out of range!\n"); + fsl_mc_printk(mci, KERN_ERR, "PFN out of range!\n"); if (err_detect & DDR_EDE_SBE) edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, @@ -337,27 +337,27 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci) row_index, 0, -1, mci->ctl_name, ""); - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect); + out_be32(pdata->mc_vbase + FSL_MC_ERR_DETECT, err_detect); } -static irqreturn_t mpc85xx_mc_isr(int irq, void *dev_id) +static irqreturn_t fsl_mc_isr(int irq, void *dev_id) { struct mem_ctl_info *mci = dev_id; - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + struct fsl_mc_pdata *pdata = mci->pvt_info; u32 err_detect; - err_detect = in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT); + err_detect = in_be32(pdata->mc_vbase + FSL_MC_ERR_DETECT); if (!err_detect) return IRQ_NONE; - mpc85xx_mc_check(mci); + fsl_mc_check(mci); return IRQ_HANDLED; } -static void mpc85xx_init_csrows(struct mem_ctl_info *mci) +static void fsl_ddr_init_csrows(struct mem_ctl_info *mci) { - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + struct fsl_mc_pdata *pdata = mci->pvt_info; struct csrow_info *csrow; struct dimm_info *dimm; u32 sdram_ctl; @@ -366,7 +366,7 @@ static void mpc85xx_init_csrows(struct mem_ctl_info *mci) u32 cs_bnds; int index; - sdram_ctl = in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG); + sdram_ctl = in_be32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG); sdtype = sdram_ctl & DSC_SDTYPE_MASK; if (sdram_ctl & DSC_RD_EN) { @@ -408,8 +408,8 @@ static void mpc85xx_init_csrows(struct mem_ctl_info *mci) csrow = mci->csrows[index]; dimm = csrow->channels[0]->dimm; - cs_bnds = in_be32(pdata->mc_vbase + MPC85XX_MC_CS_BNDS_0 + - (index * MPC85XX_MC_CS_BNDS_OFS)); + cs_bnds = in_be32(pdata->mc_vbase + FSL_MC_CS_BNDS_0 + + (index * FSL_MC_CS_BNDS_OFS)); start = (cs_bnds & 0xffff0000) >> 16; end = (cs_bnds & 0x0000ffff); @@ -434,16 +434,16 @@ static void mpc85xx_init_csrows(struct mem_ctl_info *mci) } } -int mpc85xx_mc_err_probe(struct platform_device *op) +int fsl_mc_err_probe(struct platform_device *op) { struct mem_ctl_info *mci; struct edac_mc_layer layers[2]; - struct mpc85xx_mc_pdata *pdata; + struct fsl_mc_pdata *pdata; struct resource r; u32 sdram_ctl; int res; - if (!devres_open_group(&op->dev, mpc85xx_mc_err_probe, GFP_KERNEL)) + if (!devres_open_group(&op->dev, fsl_mc_err_probe, GFP_KERNEL)) return -ENOMEM; layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; @@ -455,12 +455,12 @@ int mpc85xx_mc_err_probe(struct platform_device *op) mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), layers, sizeof(*pdata)); if (!mci) { - devres_release_group(&op->dev, mpc85xx_mc_err_probe); + devres_release_group(&op->dev, fsl_mc_err_probe); return -ENOMEM; } pdata = mci->pvt_info; - pdata->name = "mpc85xx_mc_err"; + pdata->name = "fsl_mc_err"; pdata->irq = NO_IRQ; mci->pdev = &op->dev; pdata->edac_idx = edac_mc_idx++; @@ -490,7 +490,7 @@ int mpc85xx_mc_err_probe(struct platform_device *op) goto err; } - sdram_ctl = in_be32(pdata->mc_vbase + MPC85XX_MC_DDR_SDRAM_CFG); + sdram_ctl = in_be32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG); if (!(sdram_ctl & DSC_ECC_EN)) { /* no ECC */ pr_warn("%s: No ECC DIMMs discovered\n", __func__); @@ -506,46 +506,46 @@ int mpc85xx_mc_err_probe(struct platform_device *op) mci->mod_name = EDAC_MOD_STR; if (edac_op_state == EDAC_OPSTATE_POLL) - mci->edac_check = mpc85xx_mc_check; + mci->edac_check = fsl_mc_check; mci->ctl_page_to_phys = NULL; mci->scrub_mode = SCRUB_SW_SRC; - mpc85xx_init_csrows(mci); + fsl_ddr_init_csrows(mci); /* store the original error disable bits */ orig_ddr_err_disable = - in_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE); - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE, 0); + in_be32(pdata->mc_vbase + FSL_MC_ERR_DISABLE); + out_be32(pdata->mc_vbase + FSL_MC_ERR_DISABLE, 0); /* clear all error bits */ - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, ~0); + out_be32(pdata->mc_vbase + FSL_MC_ERR_DETECT, ~0); - if (edac_mc_add_mc_with_groups(mci, mpc85xx_dev_groups)) { + if (edac_mc_add_mc_with_groups(mci, fsl_ddr_dev_groups)) { edac_dbg(3, "failed edac_mc_add_mc()\n"); goto err; } if (edac_op_state == EDAC_OPSTATE_INT) { - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_INT_EN, + out_be32(pdata->mc_vbase + FSL_MC_ERR_INT_EN, DDR_EIE_MBEE | DDR_EIE_SBEE); /* store the original error management threshold */ orig_ddr_err_sbe = in_be32(pdata->mc_vbase + - MPC85XX_MC_ERR_SBE) & 0xff0000; + FSL_MC_ERR_SBE) & 0xff0000; /* set threshold to 1 error per interrupt */ - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, 0x10000); + out_be32(pdata->mc_vbase + FSL_MC_ERR_SBE, 0x10000); /* register interrupts */ pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); res = devm_request_irq(&op->dev, pdata->irq, - mpc85xx_mc_isr, + fsl_mc_isr, IRQF_SHARED, "[EDAC] MC err", mci); if (res < 0) { - pr_err("%s: Unable to request irq %d for MPC85xx DRAM ERR\n", + pr_err("%s: Unable to request irq %d for FSL DDR DRAM ERR\n", __func__, pdata->irq); irq_dispose_mapping(pdata->irq); res = -ENODEV; @@ -556,7 +556,7 @@ int mpc85xx_mc_err_probe(struct platform_device *op) pdata->irq); } - devres_remove_group(&op->dev, mpc85xx_mc_err_probe); + devres_remove_group(&op->dev, fsl_mc_err_probe); edac_dbg(3, "success\n"); pr_info(EDAC_MOD_STR " MC err registered\n"); @@ -565,26 +565,26 @@ int mpc85xx_mc_err_probe(struct platform_device *op) err2: edac_mc_del_mc(&op->dev); err: - devres_release_group(&op->dev, mpc85xx_mc_err_probe); + devres_release_group(&op->dev, fsl_mc_err_probe); edac_mc_free(mci); return res; } -int mpc85xx_mc_err_remove(struct platform_device *op) +int fsl_mc_err_remove(struct platform_device *op) { struct mem_ctl_info *mci = dev_get_drvdata(&op->dev); - struct mpc85xx_mc_pdata *pdata = mci->pvt_info; + struct fsl_mc_pdata *pdata = mci->pvt_info; edac_dbg(0, "\n"); if (edac_op_state == EDAC_OPSTATE_INT) { - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_INT_EN, 0); + out_be32(pdata->mc_vbase + FSL_MC_ERR_INT_EN, 0); irq_dispose_mapping(pdata->irq); } - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DISABLE, + out_be32(pdata->mc_vbase + FSL_MC_ERR_DISABLE, orig_ddr_err_disable); - out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, orig_ddr_err_sbe); + out_be32(pdata->mc_vbase + FSL_MC_ERR_SBE, orig_ddr_err_sbe); edac_mc_del_mc(&op->dev); edac_mc_free(mci); diff --git a/drivers/edac/fsl_ddr_edac.h b/drivers/edac/fsl_ddr_edac.h index 2f2c2b1890b9..1eccc62b5d93 100644 --- a/drivers/edac/fsl_ddr_edac.h +++ b/drivers/edac/fsl_ddr_edac.h @@ -16,7 +16,7 @@ #ifndef _FSL_DDR_EDAC_H_ #define _FSL_DDR_EDAC_H_ -#define mpc85xx_mc_printk(mci, level, fmt, arg...) \ +#define fsl_mc_printk(mci, level, fmt, arg...) \ edac_mc_chipset_printk(mci, level, "FSL_DDR", fmt, ##arg) /* @@ -24,26 +24,23 @@ */ /* DDR_SDRAM_CFG */ -#define MPC85XX_MC_DDR_SDRAM_CFG 0x0110 -#define MPC85XX_MC_CS_BNDS_0 0x0000 -#define MPC85XX_MC_CS_BNDS_1 0x0008 -#define MPC85XX_MC_CS_BNDS_2 0x0010 -#define MPC85XX_MC_CS_BNDS_3 0x0018 -#define MPC85XX_MC_CS_BNDS_OFS 0x0008 +#define FSL_MC_DDR_SDRAM_CFG 0x0110 +#define FSL_MC_CS_BNDS_0 0x0000 +#define FSL_MC_CS_BNDS_OFS 0x0008 -#define MPC85XX_MC_DATA_ERR_INJECT_HI 0x0e00 -#define MPC85XX_MC_DATA_ERR_INJECT_LO 0x0e04 -#define MPC85XX_MC_ECC_ERR_INJECT 0x0e08 -#define MPC85XX_MC_CAPTURE_DATA_HI 0x0e20 -#define MPC85XX_MC_CAPTURE_DATA_LO 0x0e24 -#define MPC85XX_MC_CAPTURE_ECC 0x0e28 -#define MPC85XX_MC_ERR_DETECT 0x0e40 -#define MPC85XX_MC_ERR_DISABLE 0x0e44 -#define MPC85XX_MC_ERR_INT_EN 0x0e48 -#define MPC85XX_MC_CAPTURE_ATRIBUTES 0x0e4c -#define MPC85XX_MC_CAPTURE_ADDRESS 0x0e50 -#define MPC85XX_MC_CAPTURE_EXT_ADDRESS 0x0e54 -#define MPC85XX_MC_ERR_SBE 0x0e58 +#define FSL_MC_DATA_ERR_INJECT_HI 0x0e00 +#define FSL_MC_DATA_ERR_INJECT_LO 0x0e04 +#define FSL_MC_ECC_ERR_INJECT 0x0e08 +#define FSL_MC_CAPTURE_DATA_HI 0x0e20 +#define FSL_MC_CAPTURE_DATA_LO 0x0e24 +#define FSL_MC_CAPTURE_ECC 0x0e28 +#define FSL_MC_ERR_DETECT 0x0e40 +#define FSL_MC_ERR_DISABLE 0x0e44 +#define FSL_MC_ERR_INT_EN 0x0e48 +#define FSL_MC_CAPTURE_ATRIBUTES 0x0e4c +#define FSL_MC_CAPTURE_ADDRESS 0x0e50 +#define FSL_MC_CAPTURE_EXT_ADDRESS 0x0e54 +#define FSL_MC_ERR_SBE 0x0e58 #define DSC_MEM_EN 0x80000000 #define DSC_ECC_EN 0x20000000 @@ -75,12 +72,12 @@ #define DDR_EDI_SBED 0x4 /* single-bit ECC error disable */ #define DDR_EDI_MBED 0x8 /* multi-bit ECC error disable */ -struct mpc85xx_mc_pdata { +struct fsl_mc_pdata { char *name; int edac_idx; void __iomem *mc_vbase; int irq; }; -int mpc85xx_mc_err_probe(struct platform_device *op); -int mpc85xx_mc_err_remove(struct platform_device *op); +int fsl_mc_err_probe(struct platform_device *op); +int fsl_mc_err_remove(struct platform_device *op); #endif diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index c548a80f1823..0a4020923684 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -656,8 +656,8 @@ static const struct of_device_id mpc85xx_mc_err_of_match[] = { MODULE_DEVICE_TABLE(of, mpc85xx_mc_err_of_match); static struct platform_driver mpc85xx_mc_err_driver = { - .probe = mpc85xx_mc_err_probe, - .remove = mpc85xx_mc_err_remove, + .probe = fsl_mc_err_probe, + .remove = fsl_mc_err_remove, .driver = { .name = "mpc85xx_mc_err", .of_match_table = mpc85xx_mc_err_of_match, -- cgit v1.2.3 From 4e2c3252d2426cd05286e38650365f215571d3c6 Mon Sep 17 00:00:00 2001 From: York Sun Date: Tue, 9 Aug 2016 14:55:42 -0700 Subject: EDAC, fsl_ddr: Add missing DDR DRAM types The compatible DDR controllers may support DDR, DDR2, DDR3, DDR4 DRAM. An individual controller doesn't support all of them. The EDAC driver reads SDRAM_CFG to determine which mode is configured. Add DDR4 and drop the defines used only in the mtype assignment. Signed-off-by: York Sun Cc: linux-edac Cc: morbidrsa@gmail.com Cc: oss@buserror.net Cc: stuart.yoder@nxp.com Link: http://lkml.kernel.org/r/1470779760-16483-6-git-send-email-york.sun@nxp.com Signed-off-by: Borislav Petkov --- drivers/edac/fsl_ddr_edac.c | 24 ++++++++++++++++-------- drivers/edac/fsl_ddr_edac.h | 4 ---- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/edac/fsl_ddr_edac.c b/drivers/edac/fsl_ddr_edac.c index 26758337e23e..46b00e15e442 100644 --- a/drivers/edac/fsl_ddr_edac.c +++ b/drivers/edac/fsl_ddr_edac.c @@ -371,30 +371,36 @@ static void fsl_ddr_init_csrows(struct mem_ctl_info *mci) sdtype = sdram_ctl & DSC_SDTYPE_MASK; if (sdram_ctl & DSC_RD_EN) { switch (sdtype) { - case DSC_SDTYPE_DDR: + case 0x02000000: mtype = MEM_RDDR; break; - case DSC_SDTYPE_DDR2: + case 0x03000000: mtype = MEM_RDDR2; break; - case DSC_SDTYPE_DDR3: + case 0x07000000: mtype = MEM_RDDR3; break; + case 0x05000000: + mtype = MEM_RDDR4; + break; default: mtype = MEM_UNKNOWN; break; } } else { switch (sdtype) { - case DSC_SDTYPE_DDR: + case 0x02000000: mtype = MEM_DDR; break; - case DSC_SDTYPE_DDR2: + case 0x03000000: mtype = MEM_DDR2; break; - case DSC_SDTYPE_DDR3: + case 0x07000000: mtype = MEM_DDR3; break; + case 0x05000000: + mtype = MEM_DDR4; + break; default: mtype = MEM_UNKNOWN; break; @@ -499,8 +505,10 @@ int fsl_mc_err_probe(struct platform_device *op) } edac_dbg(3, "init mci\n"); - mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_RDDR2 | - MEM_FLAG_DDR | MEM_FLAG_DDR2; + mci->mtype_cap = MEM_FLAG_DDR | MEM_FLAG_RDDR | + MEM_FLAG_DDR2 | MEM_FLAG_RDDR2 | + MEM_FLAG_DDR3 | MEM_FLAG_RDDR3 | + MEM_FLAG_DDR4 | MEM_FLAG_RDDR4; mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; mci->edac_cap = EDAC_FLAG_SECDED; mci->mod_name = EDAC_MOD_STR; diff --git a/drivers/edac/fsl_ddr_edac.h b/drivers/edac/fsl_ddr_edac.h index 1eccc62b5d93..4ccee292eff1 100644 --- a/drivers/edac/fsl_ddr_edac.h +++ b/drivers/edac/fsl_ddr_edac.h @@ -50,10 +50,6 @@ #define DSC_DBW_64 0x00000000 #define DSC_SDTYPE_MASK 0x07000000 - -#define DSC_SDTYPE_DDR 0x02000000 -#define DSC_SDTYPE_DDR2 0x03000000 -#define DSC_SDTYPE_DDR3 0x07000000 #define DSC_X32_EN 0x00000020 /* Err_Int_En */ -- cgit v1.2.3 From 339fdff14c1ed34acc9c3368e01b56f80692cf83 Mon Sep 17 00:00:00 2001 From: York Sun Date: Tue, 9 Aug 2016 14:55:43 -0700 Subject: EDAC, fsl_ddr: Add support for little endian Get endianness from device tree. Both big endian and little endian are supported. Default to big endian for backwards compatibility to MPC85xx. Signed-off-by: York Sun Acked-by: Rob Herring Cc: devicetree@vger.kernel.org Cc: linux-edac Cc: morbidrsa@gmail.com Cc: oss@buserror.net Cc: stuart.yoder@nxp.com Link: http://lkml.kernel.org/r/1470779760-16483-7-git-send-email-york.sun@nxp.com Signed-off-by: Borislav Petkov --- .../bindings/memory-controllers/fsl/ddr.txt | 29 +++++++ .../devicetree/bindings/powerpc/fsl/mem-ctrlr.txt | 27 ------ drivers/edac/fsl_ddr_edac.c | 96 +++++++++++++--------- 3 files changed, 85 insertions(+), 67 deletions(-) create mode 100644 Documentation/devicetree/bindings/memory-controllers/fsl/ddr.txt delete mode 100644 Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt diff --git a/Documentation/devicetree/bindings/memory-controllers/fsl/ddr.txt b/Documentation/devicetree/bindings/memory-controllers/fsl/ddr.txt new file mode 100644 index 000000000000..dde6d837083a --- /dev/null +++ b/Documentation/devicetree/bindings/memory-controllers/fsl/ddr.txt @@ -0,0 +1,29 @@ +Freescale DDR memory controller + +Properties: + +- compatible : Should include "fsl,chip-memory-controller" where + chip is the processor (bsc9132, mpc8572 etc.), or + "fsl,qoriq-memory-controller". +- reg : Address and size of DDR controller registers +- interrupts : Error interrupt of DDR controller +- little-endian : Specifies little-endian access to registers + If omitted, big-endian will be used. + +Example 1: + + memory-controller@2000 { + compatible = "fsl,bsc9132-memory-controller"; + reg = <0x2000 0x1000>; + interrupts = <16 2 1 8>; + }; + + +Example 2: + + ddr1: memory-controller@8000 { + compatible = "fsl,qoriq-memory-controller-v4.7", + "fsl,qoriq-memory-controller"; + reg = <0x8000 0x1000>; + interrupts = <16 2 1 23>; + }; diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt b/Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt deleted file mode 100644 index f87856faf1ab..000000000000 --- a/Documentation/devicetree/bindings/powerpc/fsl/mem-ctrlr.txt +++ /dev/null @@ -1,27 +0,0 @@ -Freescale DDR memory controller - -Properties: - -- compatible : Should include "fsl,chip-memory-controller" where - chip is the processor (bsc9132, mpc8572 etc.), or - "fsl,qoriq-memory-controller". -- reg : Address and size of DDR controller registers -- interrupts : Error interrupt of DDR controller - -Example 1: - - memory-controller@2000 { - compatible = "fsl,bsc9132-memory-controller"; - reg = <0x2000 0x1000>; - interrupts = <16 2 1 8>; - }; - - -Example 2: - - ddr1: memory-controller@8000 { - compatible = "fsl,qoriq-memory-controller-v4.7", - "fsl,qoriq-memory-controller"; - reg = <0x8000 0x1000>; - interrupts = <16 2 1 23>; - }; diff --git a/drivers/edac/fsl_ddr_edac.c b/drivers/edac/fsl_ddr_edac.c index 46b00e15e442..6d4dd84a9d48 100644 --- a/drivers/edac/fsl_ddr_edac.c +++ b/drivers/edac/fsl_ddr_edac.c @@ -13,7 +13,6 @@ * the terms of the GNU General Public License version 2. This program * is licensed "as is" without any warranty of any kind, whether express * or implied. - * */ #include #include @@ -37,6 +36,20 @@ static int edac_mc_idx; static u32 orig_ddr_err_disable; static u32 orig_ddr_err_sbe; +static bool little_endian; + +static inline u32 ddr_in32(void __iomem *addr) +{ + return little_endian ? ioread32(addr) : ioread32be(addr); +} + +static inline void ddr_out32(void __iomem *addr, u32 value) +{ + if (little_endian) + iowrite32(value, addr); + else + iowrite32be(value, addr); +} /************************ MC SYSFS parts ***********************************/ @@ -49,8 +62,7 @@ static ssize_t fsl_mc_inject_data_hi_show(struct device *dev, struct mem_ctl_info *mci = to_mci(dev); struct fsl_mc_pdata *pdata = mci->pvt_info; return sprintf(data, "0x%08x", - in_be32(pdata->mc_vbase + - FSL_MC_DATA_ERR_INJECT_HI)); + ddr_in32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_HI)); } static ssize_t fsl_mc_inject_data_lo_show(struct device *dev, @@ -60,8 +72,7 @@ static ssize_t fsl_mc_inject_data_lo_show(struct device *dev, struct mem_ctl_info *mci = to_mci(dev); struct fsl_mc_pdata *pdata = mci->pvt_info; return sprintf(data, "0x%08x", - in_be32(pdata->mc_vbase + - FSL_MC_DATA_ERR_INJECT_LO)); + ddr_in32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_LO)); } static ssize_t fsl_mc_inject_ctrl_show(struct device *dev, @@ -71,7 +82,7 @@ static ssize_t fsl_mc_inject_ctrl_show(struct device *dev, struct mem_ctl_info *mci = to_mci(dev); struct fsl_mc_pdata *pdata = mci->pvt_info; return sprintf(data, "0x%08x", - in_be32(pdata->mc_vbase + FSL_MC_ECC_ERR_INJECT)); + ddr_in32(pdata->mc_vbase + FSL_MC_ECC_ERR_INJECT)); } static ssize_t fsl_mc_inject_data_hi_store(struct device *dev, @@ -81,8 +92,8 @@ static ssize_t fsl_mc_inject_data_hi_store(struct device *dev, struct mem_ctl_info *mci = to_mci(dev); struct fsl_mc_pdata *pdata = mci->pvt_info; if (isdigit(*data)) { - out_be32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_HI, - simple_strtoul(data, NULL, 0)); + ddr_out32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_HI, + simple_strtoul(data, NULL, 0)); return count; } return 0; @@ -95,8 +106,8 @@ static ssize_t fsl_mc_inject_data_lo_store(struct device *dev, struct mem_ctl_info *mci = to_mci(dev); struct fsl_mc_pdata *pdata = mci->pvt_info; if (isdigit(*data)) { - out_be32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_LO, - simple_strtoul(data, NULL, 0)); + ddr_out32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_LO, + simple_strtoul(data, NULL, 0)); return count; } return 0; @@ -109,8 +120,8 @@ static ssize_t fsl_mc_inject_ctrl_store(struct device *dev, struct mem_ctl_info *mci = to_mci(dev); struct fsl_mc_pdata *pdata = mci->pvt_info; if (isdigit(*data)) { - out_be32(pdata->mc_vbase + FSL_MC_ECC_ERR_INJECT, - simple_strtoul(data, NULL, 0)); + ddr_out32(pdata->mc_vbase + FSL_MC_ECC_ERR_INJECT, + simple_strtoul(data, NULL, 0)); return count; } return 0; @@ -256,7 +267,7 @@ static void fsl_mc_check(struct mem_ctl_info *mci) int bad_data_bit; int bad_ecc_bit; - err_detect = in_be32(pdata->mc_vbase + FSL_MC_ERR_DETECT); + err_detect = ddr_in32(pdata->mc_vbase + FSL_MC_ERR_DETECT); if (!err_detect) return; @@ -265,23 +276,23 @@ static void fsl_mc_check(struct mem_ctl_info *mci) /* no more processing if not ECC bit errors */ if (!(err_detect & (DDR_EDE_SBE | DDR_EDE_MBE))) { - out_be32(pdata->mc_vbase + FSL_MC_ERR_DETECT, err_detect); + ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DETECT, err_detect); return; } - syndrome = in_be32(pdata->mc_vbase + FSL_MC_CAPTURE_ECC); + syndrome = ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_ECC); /* Mask off appropriate bits of syndrome based on bus width */ - bus_width = (in_be32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG) & - DSC_DBW_MASK) ? 32 : 64; + bus_width = (ddr_in32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG) & + DSC_DBW_MASK) ? 32 : 64; if (bus_width == 64) syndrome &= 0xff; else syndrome &= 0xffff; err_addr = make64( - in_be32(pdata->mc_vbase + FSL_MC_CAPTURE_EXT_ADDRESS), - in_be32(pdata->mc_vbase + FSL_MC_CAPTURE_ADDRESS)); + ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_EXT_ADDRESS), + ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_ADDRESS)); pfn = err_addr >> PAGE_SHIFT; for (row_index = 0; row_index < mci->nr_csrows; row_index++) { @@ -290,8 +301,8 @@ static void fsl_mc_check(struct mem_ctl_info *mci) break; } - cap_high = in_be32(pdata->mc_vbase + FSL_MC_CAPTURE_DATA_HI); - cap_low = in_be32(pdata->mc_vbase + FSL_MC_CAPTURE_DATA_LO); + cap_high = ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_DATA_HI); + cap_low = ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_DATA_LO); /* * Analyze single-bit errors on 64-bit wide buses @@ -337,7 +348,7 @@ static void fsl_mc_check(struct mem_ctl_info *mci) row_index, 0, -1, mci->ctl_name, ""); - out_be32(pdata->mc_vbase + FSL_MC_ERR_DETECT, err_detect); + ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DETECT, err_detect); } static irqreturn_t fsl_mc_isr(int irq, void *dev_id) @@ -346,7 +357,7 @@ static irqreturn_t fsl_mc_isr(int irq, void *dev_id) struct fsl_mc_pdata *pdata = mci->pvt_info; u32 err_detect; - err_detect = in_be32(pdata->mc_vbase + FSL_MC_ERR_DETECT); + err_detect = ddr_in32(pdata->mc_vbase + FSL_MC_ERR_DETECT); if (!err_detect) return IRQ_NONE; @@ -366,7 +377,7 @@ static void fsl_ddr_init_csrows(struct mem_ctl_info *mci) u32 cs_bnds; int index; - sdram_ctl = in_be32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG); + sdram_ctl = ddr_in32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG); sdtype = sdram_ctl & DSC_SDTYPE_MASK; if (sdram_ctl & DSC_RD_EN) { @@ -414,8 +425,8 @@ static void fsl_ddr_init_csrows(struct mem_ctl_info *mci) csrow = mci->csrows[index]; dimm = csrow->channels[0]->dimm; - cs_bnds = in_be32(pdata->mc_vbase + FSL_MC_CS_BNDS_0 + - (index * FSL_MC_CS_BNDS_OFS)); + cs_bnds = ddr_in32(pdata->mc_vbase + FSL_MC_CS_BNDS_0 + + (index * FSL_MC_CS_BNDS_OFS)); start = (cs_bnds & 0xffff0000) >> 16; end = (cs_bnds & 0x0000ffff); @@ -474,6 +485,12 @@ int fsl_mc_err_probe(struct platform_device *op) mci->ctl_name = pdata->name; mci->dev_name = pdata->name; + /* + * Get the endianness of DDR controller registers. + * Default is big endian. + */ + little_endian = of_property_read_bool(op->dev.of_node, "little-endian"); + res = of_address_to_resource(op->dev.of_node, 0, &r); if (res) { pr_err("%s: Unable to get resource for MC err regs\n", @@ -496,7 +513,7 @@ int fsl_mc_err_probe(struct platform_device *op) goto err; } - sdram_ctl = in_be32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG); + sdram_ctl = ddr_in32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG); if (!(sdram_ctl & DSC_ECC_EN)) { /* no ECC */ pr_warn("%s: No ECC DIMMs discovered\n", __func__); @@ -523,12 +540,11 @@ int fsl_mc_err_probe(struct platform_device *op) fsl_ddr_init_csrows(mci); /* store the original error disable bits */ - orig_ddr_err_disable = - in_be32(pdata->mc_vbase + FSL_MC_ERR_DISABLE); - out_be32(pdata->mc_vbase + FSL_MC_ERR_DISABLE, 0); + orig_ddr_err_disable = ddr_in32(pdata->mc_vbase + FSL_MC_ERR_DISABLE); + ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DISABLE, 0); /* clear all error bits */ - out_be32(pdata->mc_vbase + FSL_MC_ERR_DETECT, ~0); + ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DETECT, ~0); if (edac_mc_add_mc_with_groups(mci, fsl_ddr_dev_groups)) { edac_dbg(3, "failed edac_mc_add_mc()\n"); @@ -536,15 +552,15 @@ int fsl_mc_err_probe(struct platform_device *op) } if (edac_op_state == EDAC_OPSTATE_INT) { - out_be32(pdata->mc_vbase + FSL_MC_ERR_INT_EN, - DDR_EIE_MBEE | DDR_EIE_SBEE); + ddr_out32(pdata->mc_vbase + FSL_MC_ERR_INT_EN, + DDR_EIE_MBEE | DDR_EIE_SBEE); /* store the original error management threshold */ - orig_ddr_err_sbe = in_be32(pdata->mc_vbase + - FSL_MC_ERR_SBE) & 0xff0000; + orig_ddr_err_sbe = ddr_in32(pdata->mc_vbase + + FSL_MC_ERR_SBE) & 0xff0000; /* set threshold to 1 error per interrupt */ - out_be32(pdata->mc_vbase + FSL_MC_ERR_SBE, 0x10000); + ddr_out32(pdata->mc_vbase + FSL_MC_ERR_SBE, 0x10000); /* register interrupts */ pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); @@ -586,13 +602,13 @@ int fsl_mc_err_remove(struct platform_device *op) edac_dbg(0, "\n"); if (edac_op_state == EDAC_OPSTATE_INT) { - out_be32(pdata->mc_vbase + FSL_MC_ERR_INT_EN, 0); irq_dispose_mapping(pdata->irq); + ddr_out32(pdata->mc_vbase + FSL_MC_ERR_INT_EN, 0); } - out_be32(pdata->mc_vbase + FSL_MC_ERR_DISABLE, - orig_ddr_err_disable); - out_be32(pdata->mc_vbase + FSL_MC_ERR_SBE, orig_ddr_err_sbe); + ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DISABLE, + orig_ddr_err_disable); + ddr_out32(pdata->mc_vbase + FSL_MC_ERR_SBE, orig_ddr_err_sbe); edac_mc_del_mc(&op->dev); edac_mc_free(mci); -- cgit v1.2.3 From 55764ed37eec48ad1c1cb6784166055e06dcb9df Mon Sep 17 00:00:00 2001 From: York Sun Date: Tue, 9 Aug 2016 14:55:44 -0700 Subject: EDAC, fsl_ddr: Fix IRQ dispose warning when module is removed When compiled as a module, removing it causes kernel warnings when irq_dispose_mapping() is called. Instead of calling irq_of_parse_and_map(), use platform_get_irq() to acquire the IRQ number. Signed-off-by: York Sun Cc: linux-edac Cc: morbidrsa@gmail.com Cc: oss@buserror.net Cc: stuart.yoder@nxp.com Link: http://lkml.kernel.org/r/1470779760-16483-8-git-send-email-york.sun@nxp.com Signed-off-by: Borislav Petkov --- drivers/edac/fsl_ddr_edac.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/edac/fsl_ddr_edac.c b/drivers/edac/fsl_ddr_edac.c index 6d4dd84a9d48..d8ce1f635c38 100644 --- a/drivers/edac/fsl_ddr_edac.c +++ b/drivers/edac/fsl_ddr_edac.c @@ -563,7 +563,7 @@ int fsl_mc_err_probe(struct platform_device *op) ddr_out32(pdata->mc_vbase + FSL_MC_ERR_SBE, 0x10000); /* register interrupts */ - pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0); + pdata->irq = platform_get_irq(op, 0); res = devm_request_irq(&op->dev, pdata->irq, fsl_mc_isr, IRQF_SHARED, @@ -571,7 +571,6 @@ int fsl_mc_err_probe(struct platform_device *op) if (res < 0) { pr_err("%s: Unable to request irq %d for FSL DDR DRAM ERR\n", __func__, pdata->irq); - irq_dispose_mapping(pdata->irq); res = -ENODEV; goto err2; } @@ -602,7 +601,6 @@ int fsl_mc_err_remove(struct platform_device *op) edac_dbg(0, "\n"); if (edac_op_state == EDAC_OPSTATE_INT) { - irq_dispose_mapping(pdata->irq); ddr_out32(pdata->mc_vbase + FSL_MC_ERR_INT_EN, 0); } -- cgit v1.2.3 From eeb3d68b6c83abdb80bc0823cbb77cd49484793c Mon Sep 17 00:00:00 2001 From: York Sun Date: Tue, 23 Aug 2016 15:14:03 -0700 Subject: EDAC, layerscape: Add Layerscape EDAC support Add DDR EDAC driver for ARM-based compatible controllers. Both big-endian and little-endian are supported, as specified in device tree. Signed-off-by: York Sun Cc: linux-arm-kernel@lists.infradead.org Cc: linux-edac Link: http://lkml.kernel.org/r/1471990465-27443-1-git-send-email-york.sun@nxp.com Signed-off-by: Borislav Petkov --- arch/arm64/Kconfig.platforms | 1 + drivers/edac/Kconfig | 7 ++++ drivers/edac/Makefile | 3 ++ drivers/edac/fsl_ddr_edac.c | 2 +- drivers/edac/layerscape_edac.c | 73 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 drivers/edac/layerscape_edac.c diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index bb2616b16157..52f30a62e6e5 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -55,6 +55,7 @@ config ARCH_EXYNOS config ARCH_LAYERSCAPE bool "ARMv8 based Freescale Layerscape SoC family" + select EDAC_SUPPORT help This enables support for the Freescale Layerscape SoC family. diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 394cd16dd58f..49d79002f69c 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -258,6 +258,13 @@ config EDAC_MPC85XX Support for error detection and correction on the Freescale MPC8349, MPC8560, MPC8540, MPC8548, T4240 +config EDAC_LAYERSCAPE + tristate "Freescale Layerscape DDR" + depends on EDAC_MM_EDAC && ARCH_LAYERSCAPE + help + Support for error detection and correction on Freescale memory + controllers on Layerscape SoCs. + config EDAC_MV64X60 tristate "Marvell MV64x60" depends on EDAC_MM_EDAC && MV64X60 diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index ee047a415722..910dc83d3629 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -54,6 +54,9 @@ obj-$(CONFIG_EDAC_PASEMI) += pasemi_edac.o mpc85xx_edac_mod-y := fsl_ddr_edac.o mpc85xx_edac.o obj-$(CONFIG_EDAC_MPC85XX) += mpc85xx_edac_mod.o +layerscape_edac_mod-y := fsl_ddr_edac.o layerscape_edac.o +obj-$(CONFIG_EDAC_LAYERSCAPE) += layerscape_edac_mod.o + obj-$(CONFIG_EDAC_MV64X60) += mv64x60_edac.o obj-$(CONFIG_EDAC_CELL) += cell_edac.o obj-$(CONFIG_EDAC_PPC4XX) += ppc4xx_edac.o diff --git a/drivers/edac/fsl_ddr_edac.c b/drivers/edac/fsl_ddr_edac.c index d8ce1f635c38..afade14c3e93 100644 --- a/drivers/edac/fsl_ddr_edac.c +++ b/drivers/edac/fsl_ddr_edac.c @@ -26,6 +26,7 @@ #include #include +#include #include "edac_module.h" #include "edac_core.h" #include "fsl_ddr_edac.h" @@ -478,7 +479,6 @@ int fsl_mc_err_probe(struct platform_device *op) pdata = mci->pvt_info; pdata->name = "fsl_mc_err"; - pdata->irq = NO_IRQ; mci->pdev = &op->dev; pdata->edac_idx = edac_mc_idx++; dev_set_drvdata(mci->pdev, mci); 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 @@ +/* + * Freescale Memory Controller kernel module + * + * Author: York Sun + * + * Copyright 2016 NXP Semiconductor + * + * Derived from mpc85xx_edac.c + * Author: Dave Jiang + * + * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include "edac_core.h" +#include "fsl_ddr_edac.h" + +static const struct of_device_id fsl_ddr_mc_err_of_match[] = { + { .compatible = "fsl,qoriq-memory-controller", }, + {}, +}; +MODULE_DEVICE_TABLE(of, fsl_ddr_mc_err_of_match); + +static struct platform_driver fsl_ddr_mc_err_driver = { + .probe = fsl_mc_err_probe, + .remove = fsl_mc_err_remove, + .driver = { + .name = "fsl_ddr_mc_err", + .of_match_table = fsl_ddr_mc_err_of_match, + }, +}; + +static int __init fsl_ddr_mc_init(void) +{ + int res; + + /* make sure error reporting method is sane */ + switch (edac_op_state) { + case EDAC_OPSTATE_POLL: + case EDAC_OPSTATE_INT: + break; + default: + edac_op_state = EDAC_OPSTATE_INT; + break; + } + + res = platform_driver_register(&fsl_ddr_mc_err_driver); + if (res) { + pr_err("MC fails to register\n"); + return res; + } + + return 0; +} + +module_init(fsl_ddr_mc_init); + +static void __exit fsl_ddr_mc_exit(void) +{ + platform_driver_unregister(&fsl_ddr_mc_err_driver); +} + +module_exit(fsl_ddr_mc_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("NXP Semiconductor"); +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, + "EDAC Error Reporting state: 0=Poll, 2=Interrupt"); -- cgit v1.2.3 From f47ae798d82fb0d77d76b3b3f700d0e61f73d7c1 Mon Sep 17 00:00:00 2001 From: York Sun Date: Tue, 23 Aug 2016 15:16:10 -0700 Subject: EDAC, fsl_ddr: Replace simple_strtoul() with kstrtoul() Replace obsolete simple_strtoul() with kstrtoul(). Signed-off-by: York Sun Cc: linux-edac Link: http://lkml.kernel.org/r/1471990593-27536-1-git-send-email-york.sun@nxp.com Signed-off-by: Borislav Petkov --- drivers/edac/fsl_ddr_edac.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/edac/fsl_ddr_edac.c b/drivers/edac/fsl_ddr_edac.c index afade14c3e93..4ddf8382369f 100644 --- a/drivers/edac/fsl_ddr_edac.c +++ b/drivers/edac/fsl_ddr_edac.c @@ -92,9 +92,15 @@ static ssize_t fsl_mc_inject_data_hi_store(struct device *dev, { struct mem_ctl_info *mci = to_mci(dev); struct fsl_mc_pdata *pdata = mci->pvt_info; + unsigned long val; + int rc; + if (isdigit(*data)) { - ddr_out32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_HI, - simple_strtoul(data, NULL, 0)); + rc = kstrtoul(data, 0, &val); + if (rc) + return rc; + + ddr_out32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_HI, val); return count; } return 0; @@ -106,9 +112,15 @@ static ssize_t fsl_mc_inject_data_lo_store(struct device *dev, { struct mem_ctl_info *mci = to_mci(dev); struct fsl_mc_pdata *pdata = mci->pvt_info; + unsigned long val; + int rc; + if (isdigit(*data)) { - ddr_out32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_LO, - simple_strtoul(data, NULL, 0)); + rc = kstrtoul(data, 0, &val); + if (rc) + return rc; + + ddr_out32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_LO, val); return count; } return 0; @@ -120,9 +132,15 @@ static ssize_t fsl_mc_inject_ctrl_store(struct device *dev, { struct mem_ctl_info *mci = to_mci(dev); struct fsl_mc_pdata *pdata = mci->pvt_info; + unsigned long val; + int rc; + if (isdigit(*data)) { - ddr_out32(pdata->mc_vbase + FSL_MC_ECC_ERR_INJECT, - simple_strtoul(data, NULL, 0)); + rc = kstrtoul(data, 0, &val); + if (rc) + return rc; + + ddr_out32(pdata->mc_vbase + FSL_MC_ECC_ERR_INJECT, val); return count; } return 0; -- cgit v1.2.3 From c91d907596cc44e8206b707e6be80f5489db4f40 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 1 Sep 2016 14:55:45 +0200 Subject: EDAC, I3000: Orphan driver Apparently there's no hw left at Intel for testing patches and Jason is not going to maintain it anymore. Signed-off-by: Borislav Petkov --- CREDITS | 4 ++++ MAINTAINERS | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CREDITS b/CREDITS index 2a3fbcd229e6..1d7c43f3361f 100644 --- a/CREDITS +++ b/CREDITS @@ -3654,6 +3654,10 @@ S: Obere Heerbergstrasse 17 S: 97078 Wuerzburg S: Germany +N: Jason Uhlenkott +E: juhlenko@akamai.com +D: I3000 EDAC driver + N: Greg Ungerer E: gerg@snapgear.com D: uClinux kernel hacker diff --git a/MAINTAINERS b/MAINTAINERS index 20bb1d00098c..13c6abeb451a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4454,9 +4454,8 @@ S: Maintained F: drivers/edac/i82443bxgx_edac.c EDAC-I3000 -M: Jason Uhlenkott L: linux-edac@vger.kernel.org -S: Maintained +S: Orphan F: drivers/edac/i3000_edac.c EDAC-I5000 -- cgit v1.2.3 From 01f0c2164d4328fa45d054af0e3949dd3f472e30 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 8 Sep 2016 18:20:09 +0200 Subject: EDAC: Move Doug Thompson to CREDITS Doug hasn't been active as a maintainer for a long time now. Move him to CREDITS. Thanks for all the hard work, Doug! Signed-off-by: Borislav Petkov Cc: Doug Thompson Cc: Doug Thompson --- CREDITS | 4 ++++ MAINTAINERS | 6 ------ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/CREDITS b/CREDITS index 1d7c43f3361f..c3cbd1bbe3b0 100644 --- a/CREDITS +++ b/CREDITS @@ -3518,6 +3518,10 @@ S: 145 Howard St. S: Northborough, MA 01532 S: USA +N: Doug Thompson +E: dougthompson@xmission.com +D: EDAC + N: Tommy Thorn E: Tommy.Thorn@irisa.fr W: http://www.irisa.fr/prive/thorn/index.html diff --git a/MAINTAINERS b/MAINTAINERS index 13c6abeb451a..8350e19190bb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4393,7 +4393,6 @@ F: Documentation/filesystems/ecryptfs.txt F: fs/ecryptfs/ EDAC-CORE -M: Doug Thompson M: Borislav Petkov M: Mauro Carvalho Chehab M: Mauro Carvalho Chehab @@ -4406,14 +4405,12 @@ F: drivers/edac/ F: include/linux/edac.h EDAC-AMD64 -M: Doug Thompson M: Borislav Petkov L: linux-edac@vger.kernel.org S: Maintained F: drivers/edac/amd64_edac* EDAC-CALXEDA -M: Doug Thompson M: Robert Richter L: linux-edac@vger.kernel.org S: Maintained @@ -4429,13 +4426,11 @@ F: drivers/edac/octeon_edac* EDAC-E752X M: Mark Gross -M: Doug Thompson L: linux-edac@vger.kernel.org S: Maintained F: drivers/edac/e752x_edac.c EDAC-E7XXX -M: Doug Thompson L: linux-edac@vger.kernel.org S: Maintained F: drivers/edac/e7xxx_edac.c @@ -4459,7 +4454,6 @@ S: Orphan F: drivers/edac/i3000_edac.c EDAC-I5000 -M: Doug Thompson L: linux-edac@vger.kernel.org S: Maintained F: drivers/edac/i5000_edac.c -- cgit v1.2.3 From 7d136731e9ba695a6cf775c3a804456eeef4527e Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 8 Sep 2016 19:13:29 +0200 Subject: EDAC, fsl_ddr: Add entry to MAINTAINERS Add York as the maintainer so that get_maintainers.pl can find him on patches. Signed-off-by: Borislav Petkov Acked-by: York Sun --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 8350e19190bb..b6ecf5715c98 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4435,6 +4435,12 @@ L: linux-edac@vger.kernel.org S: Maintained F: drivers/edac/e7xxx_edac.c +EDAC-FSL_DDR +M: York Sun +L: linux-edac@vger.kernel.org +S: Maintained +F: drivers/edac/fsl_ddr_edac.* + EDAC-GHES M: Mauro Carvalho Chehab M: Mauro Carvalho Chehab -- cgit v1.2.3 From 43fa9ba632bd90b5cf63793a461e28df6af4387a Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 8 Sep 2016 15:58:04 +0000 Subject: EDAC, fsl_ddr: Fix error return code in fsl_mc_err_probe() Return negative error code from the edac_mc_add_mc() error handling case instead of 0, as done elsewhere in this function. Signed-off-by: Wei Yongjun Acked-by: York Sun Cc: linux-edac Link: http://lkml.kernel.org/r/1473350284-26482-1-git-send-email-weiyj.lk@gmail.com Signed-off-by: Borislav Petkov --- drivers/edac/fsl_ddr_edac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/edac/fsl_ddr_edac.c b/drivers/edac/fsl_ddr_edac.c index 4ddf8382369f..9774f52f0c3e 100644 --- a/drivers/edac/fsl_ddr_edac.c +++ b/drivers/edac/fsl_ddr_edac.c @@ -564,7 +564,8 @@ int fsl_mc_err_probe(struct platform_device *op) /* clear all error bits */ ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DETECT, ~0); - if (edac_mc_add_mc_with_groups(mci, fsl_ddr_dev_groups)) { + res = edac_mc_add_mc_with_groups(mci, fsl_ddr_dev_groups); + if (res) { edac_dbg(3, "failed edac_mc_add_mc()\n"); goto err; } -- cgit v1.2.3 From 372095723a597f4d27f561abab9b3da4c8a33106 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 12 Sep 2016 20:00:36 +1000 Subject: EDAC: Remove NO_IRQ from powerpc-only drivers We'd like to eventually remove NO_IRQ on powerpc, so remove usages of it from powerpc-only drivers. The pdata structs are kzalloc'ed, so we don't need to initialise those to 0, we can just drop the assignments entirely. Signed-off-by: Michael Ellerman Cc: Arnd Bergmann Cc: Johannes Thumshirn Cc: linux-edac Cc: linuxppc-dev@ozlabs.org Link: http://lkml.kernel.org/r/1473674436-19467-1-git-send-email-mpe@ellerman.id.au Signed-off-by: Borislav Petkov --- drivers/edac/mpc85xx_edac.c | 2 -- drivers/edac/mv64x60_edac.c | 4 ---- drivers/edac/ppc4xx_edac.c | 4 +--- 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index 0a4020923684..ff0567526ee3 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -170,7 +170,6 @@ static int mpc85xx_pci_err_probe(struct platform_device *op) pdata = pci->pvt_info; pdata->name = "mpc85xx_pci_err"; - pdata->irq = NO_IRQ; plat_data = op->dev.platform_data; if (!plat_data) { @@ -491,7 +490,6 @@ static int mpc85xx_l2_err_probe(struct platform_device *op) pdata = edac_dev->pvt_info; pdata->name = "mpc85xx_l2_err"; - pdata->irq = NO_IRQ; edac_dev->dev = &op->dev; dev_set_drvdata(edac_dev->dev, edac_dev); edac_dev->ctl_name = pdata->name; 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) pdata->pci_hose = pdev->id; pdata->name = "mpc85xx_pci_err"; - pdata->irq = NO_IRQ; platform_set_drvdata(pdev, pci); pci->dev = &pdev->dev; pci->dev_name = dev_name(&pdev->dev); @@ -291,7 +290,6 @@ static int mv64x60_sram_err_probe(struct platform_device *pdev) pdata = edac_dev->pvt_info; pdata->name = "mv64x60_sram_err"; - pdata->irq = NO_IRQ; edac_dev->dev = &pdev->dev; platform_set_drvdata(pdev, edac_dev); edac_dev->dev_name = dev_name(&pdev->dev); @@ -459,7 +457,6 @@ static int mv64x60_cpu_err_probe(struct platform_device *pdev) pdata = edac_dev->pvt_info; pdata->name = "mv64x60_cpu_err"; - pdata->irq = NO_IRQ; edac_dev->dev = &pdev->dev; platform_set_drvdata(pdev, edac_dev); edac_dev->dev_name = dev_name(&pdev->dev); @@ -727,7 +724,6 @@ static int mv64x60_mc_err_probe(struct platform_device *pdev) mci->pdev = &pdev->dev; platform_set_drvdata(pdev, mci); pdata->name = "mv64x60_mc_err"; - pdata->irq = NO_IRQ; mci->dev_name = dev_name(&pdev->dev); pdata->edac_idx = edac_mc_idx++; 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, pdata = mci->pvt_info; pdata->dcr_host = *dcr_host; - pdata->irqs.sec = NO_IRQ; - pdata->irqs.ded = NO_IRQ; /* Initialize controller capabilities and configuration */ @@ -1111,7 +1109,7 @@ static int ppc4xx_edac_register_irq(struct platform_device *op, ded_irq = irq_of_parse_and_map(np, INTMAP_ECCDED_INDEX); sec_irq = irq_of_parse_and_map(np, INTMAP_ECCSEC_INDEX); - if (ded_irq == NO_IRQ || sec_irq == NO_IRQ) { + if (!ded_irq || !sec_irq) { ppc4xx_edac_mc_printk(KERN_ERR, mci, "Unable to map interrupts.\n"); status = -ENODEV; -- cgit v1.2.3 From c7c35407cd8654b5ee138b6f1dbb24dc62a3f3c0 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 8 Sep 2016 09:38:01 +0100 Subject: EDAC, sb_edac: Remove NULL pointer check on array pci_tad pvt->pci_tad is a NUM_CHANNELS array of struct pci_dev pointers and hence cannot be NULL, so the NULL pointer check on pci_tad is redundant. Remove it. Signed-off-by: Colin Ian King Acked-by: Tony Luck Cc: linux-edac Link: http://lkml.kernel.org/r/20160908083801.14766-1-colin.king@canonical.com Signed-off-by: Borislav Petkov --- drivers/edac/sb_edac.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 4fb2eb7c800d..04aafdda9e98 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, /* Check if everything were registered */ if (!pvt->pci_sad0 || !pvt->pci_sad1 || !pvt->pci_ha0 || - !pvt-> pci_tad || !pvt->pci_ras || !pvt->pci_ta) + !pvt->pci_ras || !pvt->pci_ta) goto enodev; if (saw_chan_mask != 0x0f) @@ -2563,8 +2563,7 @@ static int ibridge_mci_bind_devs(struct mem_ctl_info *mci, /* Check if everything were registered */ if (!pvt->pci_sad0 || !pvt->pci_ha0 || !pvt->pci_br0 || - !pvt->pci_br1 || !pvt->pci_tad || !pvt->pci_ras || - !pvt->pci_ta) + !pvt->pci_br1 || !pvt->pci_ras || !pvt->pci_ta) goto enodev; if (saw_chan_mask != 0x0f && /* -EN */ -- cgit v1.2.3 From d6efab74f67249fa18cdf6b5420f9787db195f85 Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Thu, 15 Sep 2016 19:07:17 -0500 Subject: EDAC, amd64: Autoload module using x86_cpu_id Reinstate driver autoloading now that PCI dependency is gone. Signed-off-by: Yazen Ghannam Cc: linux-edac Link: http://lkml.kernel.org/r/1473984445-1726-2-git-send-email-Yazen.Ghannam@amd.com Signed-off-by: Borislav Petkov --- drivers/edac/amd64_edac.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index da43404dbd0c..ee181c53626f 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -2970,6 +2970,15 @@ static void setup_pci_device(void) } } +static const struct x86_cpu_id amd64_cpuids[] = { + { X86_VENDOR_AMD, 0xF, X86_MODEL_ANY, X86_FEATURE_ANY, 0 }, + { X86_VENDOR_AMD, 0x10, X86_MODEL_ANY, X86_FEATURE_ANY, 0 }, + { X86_VENDOR_AMD, 0x15, X86_MODEL_ANY, X86_FEATURE_ANY, 0 }, + { X86_VENDOR_AMD, 0x16, X86_MODEL_ANY, X86_FEATURE_ANY, 0 }, + { } +}; +MODULE_DEVICE_TABLE(x86cpu, amd64_cpuids); + static int __init amd64_edac_init(void) { int err = -ENODEV; -- cgit v1.2.3 From 3763569f4c86ff3ea224c822821a4313c9cadde9 Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Thu, 22 Sep 2016 17:13:38 -0500 Subject: EDAC, altera: Correct EDAC IRQ error message Correct the error message sent out in the case of a single bit error IRQ allocation. Signed-off-by: Thor Thayer Cc: linux-edac Link: http://lkml.kernel.org/r/1474582419-7053-1-git-send-email-tthayer@opensource.altera.com Signed-off-by: Borislav Petkov --- drivers/edac/altera_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 817e8919cfe6..afe630540956 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -1749,7 +1749,7 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, prv->ecc_irq_handler, IRQF_SHARED, ecc_name, altdev); if (rc) { - edac_printk(KERN_ERR, EDAC_DEVICE, "No DBERR IRQ resource\n"); + edac_printk(KERN_ERR, EDAC_DEVICE, "No SBERR IRQ resource\n"); goto err_release_group1; } -- cgit v1.2.3 From a29d64a45eed1ee0d4ac90335da79ad1a9a0990d Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Thu, 22 Sep 2016 17:13:39 -0500 Subject: EDAC, altera: Add IRQ Flags to disable IRQ while handling Add the IRQF_ONESHOT and IRQF_TRIGGER_HIGH flags to disable the IRQ while executing the IRQ handler. Remove the IRQF_SHARED because these are not shared IRQs in the domain. Exposed when flooding IRQs. Signed-off-by: Thor Thayer Cc: linux-edac Link: http://lkml.kernel.org/r/1474582419-7053-2-git-send-email-tthayer@opensource.altera.com Signed-off-by: Borislav Petkov --- drivers/edac/altera_edac.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index afe630540956..58d3e2b39b5b 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -1445,7 +1445,8 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) } rc = devm_request_irq(&altdev->ddev, altdev->sb_irq, prv->ecc_irq_handler, - IRQF_SHARED, ecc_name, altdev); + IRQF_ONESHOT | IRQF_TRIGGER_HIGH, + ecc_name, altdev); if (rc) { edac_printk(KERN_ERR, EDAC_DEVICE, "PortB SBERR IRQ error\n"); goto err_release_group_1; @@ -1459,7 +1460,8 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) } rc = devm_request_irq(&altdev->ddev, altdev->db_irq, prv->ecc_irq_handler, - IRQF_SHARED, ecc_name, altdev); + IRQF_ONESHOT | IRQF_TRIGGER_HIGH, + ecc_name, altdev); if (rc) { edac_printk(KERN_ERR, EDAC_DEVICE, "PortB DBERR IRQ error\n"); goto err_release_group_1; @@ -1745,9 +1747,9 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, rc = -ENODEV; goto err_release_group1; } - rc = devm_request_irq(edac->dev, altdev->sb_irq, - prv->ecc_irq_handler, - IRQF_SHARED, ecc_name, altdev); + rc = devm_request_irq(edac->dev, altdev->sb_irq, prv->ecc_irq_handler, + IRQF_ONESHOT | IRQF_TRIGGER_HIGH, + ecc_name, altdev); if (rc) { edac_printk(KERN_ERR, EDAC_DEVICE, "No SBERR IRQ resource\n"); goto err_release_group1; @@ -1759,9 +1761,9 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, rc = -ENODEV; goto err_release_group1; } - rc = devm_request_irq(edac->dev, altdev->db_irq, - prv->ecc_irq_handler, - IRQF_SHARED, ecc_name, altdev); + rc = devm_request_irq(edac->dev, altdev->db_irq, prv->ecc_irq_handler, + IRQF_ONESHOT | IRQF_TRIGGER_HIGH, + ecc_name, altdev); if (rc) { edac_printk(KERN_ERR, EDAC_DEVICE, "No DBERR IRQ resource\n"); goto err_release_group1; -- cgit v1.2.3