Merge tag 'edac_for_5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 7 May 2019 02:53:11 +0000 (19:53 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 7 May 2019 02:53:11 +0000 (19:53 -0700)
Pull EDAC updates from Borislav Petkov:

 - amd64_edac: Family 0x17, models 0x30-.. enablement (Yazen Ghannam)

 - skx_*: Librarize it so that it can be shared between drivers (Qiuxu Zhuo)

 - altera: Stratix10 improvements (Thor Thayer)

 - The usual round of fixes, fixlets and cleanups

* tag 'edac_for_5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp:
  Revert "EDAC/amd64: Support more than two controllers for chip select handling"
  arm64: dts: stratix10: Use new Stratix10 EDAC bindings
  Documentation: dt: edac: Add Stratix10 Peripheral bindings
  Documentation: dt: edac: Fix Stratix10 IRQ bindings
  EDAC/altera, firmware/intel: Add Stratix10 ECC DBE SMC call
  EDAC/altera: Initialize peripheral FIFOs in probe()
  EDAC/altera: Do less intrusive error injection
  EDAC/amd64: Adjust printed chip select sizes when interleaved
  EDAC/amd64: Support more than two controllers for chip select handling
  EDAC/amd64: Recognize x16 symbol size
  EDAC/amd64: Set maximum channel layer size depending on family
  EDAC/amd64: Support more than two Unified Memory Controllers
  EDAC/amd64: Use a macro for iterating over Unified Memory Controllers
  EDAC/amd64: Add Family 17h Model 30h PCI IDs
  MAINTAINERS: Add entry for EDAC-I10NM
  MAINTAINERS: Update entry for EDAC-SKYLAKE
  EDAC, altera: Fix S10 Double Bit Error Notification
  EDAC, skx, i10nm: Make skx_common.c a pure library

12 files changed:
Documentation/devicetree/bindings/edac/socfpga-eccmgr.txt
MAINTAINERS
arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi
drivers/edac/altera_edac.c
drivers/edac/altera_edac.h
drivers/edac/amd64_edac.c
drivers/edac/amd64_edac.h
drivers/edac/i10nm_base.c
drivers/edac/skx_base.c
drivers/edac/skx_common.c
drivers/edac/skx_common.h
include/linux/firmware/intel/stratix10-smc.h

index 5626560a6cfdff805ebd1460a14ec2127747de4a..8f52206cfd2a1bcaa7f83b1bb127264b709bad3a 100644 (file)
@@ -232,37 +232,152 @@ Example:
                };
        };
 
-Stratix10 SoCFPGA ECC Manager
+Stratix10 SoCFPGA ECC Manager (ARM64)
 The Stratix10 SoC ECC Manager handles the IRQs for each peripheral
-in a shared register similar to the Arria10. However, ECC requires
-access to registers that can only be read from Secure Monitor with
-SMC calls. Therefore the device tree is slightly different.
+in a shared register similar to the Arria10. However, Stratix10 ECC
+requires access to registers that can only be read from Secure Monitor
+with SMC calls. Therefore the device tree is slightly different. Note
+that only 1 interrupt is sent in Stratix10 because the double bit errors
+are treated as SErrors in ARM64 instead of IRQs in ARM32.
 
 Required Properties:
 - compatible : Should be "altr,socfpga-s10-ecc-manager"
-- interrupts : Should be single bit error interrupt, then double bit error
-       interrupt.
+- altr,sysgr-syscon : phandle to Stratix10 System Manager Block
+                     containing the ECC manager registers.
+- interrupts : Should be single bit error interrupt.
 - interrupt-controller : boolean indicator that ECC Manager is an interrupt controller
 - #interrupt-cells : must be set to 2.
+- #address-cells: must be 1
+- #size-cells: must be 1
+- ranges : standard definition, should translate from local addresses
 
 Subcomponents:
 
 SDRAM ECC
 Required Properties:
 - compatible : Should be "altr,sdram-edac-s10"
-- interrupts : Should be single bit error interrupt, then double bit error
-       interrupt, in this order.
+- interrupts : Should be single bit error interrupt.
+
+On-Chip RAM ECC
+Required Properties:
+- compatible      : Should be "altr,socfpga-s10-ocram-ecc"
+- reg             : Address and size for ECC block registers.
+- altr,ecc-parent : phandle to parent OCRAM node.
+- interrupts      : Should be single bit error interrupt.
+
+Ethernet FIFO ECC
+Required Properties:
+- compatible      : Should be "altr,socfpga-s10-eth-mac-ecc"
+- reg             : Address and size for ECC block registers.
+- altr,ecc-parent : phandle to parent Ethernet node.
+- interrupts      : Should be single bit error interrupt.
+
+NAND FIFO ECC
+Required Properties:
+- compatible      : Should be "altr,socfpga-s10-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.
+
+DMA FIFO ECC
+Required Properties:
+- compatible      : Should be "altr,socfpga-s10-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.
+
+USB FIFO ECC
+Required Properties:
+- compatible      : Should be "altr,socfpga-s10-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.
+
+SDMMC FIFO ECC
+Required Properties:
+- compatible      : Should be "altr,socfpga-s10-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 for port A
+                   and then single bit error interrupt for port B.
 
 Example:
 
        eccmgr {
                compatible = "altr,socfpga-s10-ecc-manager";
-               interrupts = <0 15 4>, <0 95 4>;
+               altr,sysmgr-syscon = <&sysmgr>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               interrupts = <0 15 4>;
                interrupt-controller;
                #interrupt-cells = <2>;
+               ranges;
 
                sdramedac {
                        compatible = "altr,sdram-edac-s10";
-                       interrupts = <16 4>, <48 4>;
+                       interrupts = <16 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
+               ocram-ecc@ff8cc000 {
+                       compatible = "altr,socfpga-s10-ocram-ecc";
+                       reg = <ff8cc000 0x100>;
+                       altr,ecc-parent = <&ocram>;
+                       interrupts = <1 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
+               emac0-rx-ecc@ff8c0000 {
+                       compatible = "altr,socfpga-s10-eth-mac-ecc";
+                       reg = <0xff8c0000 0x100>;
+                       altr,ecc-parent = <&gmac0>;
+                       interrupts = <4 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
+               emac0-tx-ecc@ff8c0400 {
+                       compatible = "altr,socfpga-s10-eth-mac-ecc";
+                       reg = <0xff8c0400 0x100>;
+                       altr,ecc-parent = <&gmac0>;
+                       interrupts = <5 IRQ_TYPE_LEVEL_HIGH>'
+               };
+
+               nand-buf-ecc@ff8c8000 {
+                       compatible = "altr,socfpga-s10-nand-ecc";
+                       reg = <0xff8c8000 0x100>;
+                       altr,ecc-parent = <&nand>;
+                       interrupts = <11 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
+               nand-rd-ecc@ff8c8400 {
+                       compatible = "altr,socfpga-s10-nand-ecc";
+                       reg = <0xff8c8400 0x100>;
+                       altr,ecc-parent = <&nand>;
+                       interrupts = <13 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
+               nand-wr-ecc@ff8c8800 {
+                       compatible = "altr,socfpga-s10-nand-ecc";
+                       reg = <0xff8c8800 0x100>;
+                       altr,ecc-parent = <&nand>;
+                       interrupts = <12 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
+               dma-ecc@ff8c9000 {
+                       compatible = "altr,socfpga-s10-dma-ecc";
+                       reg = <0xff8c9000 0x100>;
+                       altr,ecc-parent = <&pdma>;
+                       interrupts = <10 IRQ_TYPE_LEVEL_HIGH>;
+
+               usb0-ecc@ff8c4000 {
+                       compatible = "altr,socfpga-s10-usb-ecc";
+                       reg = <0xff8c4000 0x100>;
+                       altr,ecc-parent = <&usb0>;
+                       interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
+               };
+
+               sdmmc-ecc@ff8c8c00 {
+                       compatible = "altr,socfpga-s10-sdmmc-ecc";
+                       reg = <0xff8c8c00 0x100>;
+                       altr,ecc-parent = <&mmc>;
+                       interrupts = <14 IRQ_TYPE_LEVEL_HIGH>,
+                                    <15 IRQ_TYPE_LEVEL_HIGH>;
                };
        };
index bd40a852207bafb79e2ba1161b3882b07a518b2c..58c1b7a35711b5585abe7d5d8e58f3336a68df58 100644 (file)
@@ -5599,6 +5599,12 @@ L:       linux-edac@vger.kernel.org
 S:     Maintained
 F:     drivers/edac/ghes_edac.c
 
+EDAC-I10NM
+M:     Tony Luck <tony.luck@intel.com>
+L:     linux-edac@vger.kernel.org
+S:     Maintained
+F:     drivers/edac/i10nm_base.c
+
 EDAC-I3000
 L:     linux-edac@vger.kernel.org
 S:     Orphan
@@ -5680,7 +5686,7 @@ EDAC-SKYLAKE
 M:     Tony Luck <tony.luck@intel.com>
 L:     linux-edac@vger.kernel.org
 S:     Maintained
-F:     drivers/edac/skx_edac.c
+F:     drivers/edac/skx_*.c
 
 EDAC-TI
 M:     Tero Kristo <t-kristo@ti.com>
index cd7c76e58b09a60f75ccd510083bab730a2378b0..a2cec6218211b6aad8ff5e1da84c6aee750ebd50 100644 (file)
                };
 
                eccmgr {
-                       compatible = "altr,socfpga-a10-ecc-manager";
+                       compatible = "altr,socfpga-s10-ecc-manager",
+                                    "altr,socfpga-a10-ecc-manager";
                        altr,sysmgr-syscon = <&sysmgr>;
                        #address-cells = <1>;
                        #size-cells = <1>;
-                       interrupts = <0 15 4>, <0 95 4>;
+                       interrupts = <0 15 4>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
                        ranges;
                        sdramedac {
                                compatible = "altr,sdram-edac-s10";
                                altr,sdr-syscon = <&sdr>;
-                               interrupts = <16 4>, <48 4>;
+                               interrupts = <16 4>;
                        };
 
                        usb0-ecc@ff8c4000 {
-                               compatible = "altr,socfpga-usb-ecc";
+                               compatible = "altr,socfpga-s10-usb-ecc",
+                                            "altr,socfpga-usb-ecc";
                                reg = <0xff8c4000 0x100>;
                                altr,ecc-parent = <&usb0>;
-                               interrupts = <2 4>,
-                                            <34 4>;
+                               interrupts = <2 4>;
                        };
 
                        emac0-rx-ecc@ff8c0000 {
-                               compatible = "altr,socfpga-eth-mac-ecc";
+                               compatible = "altr,socfpga-s10-eth-mac-ecc",
+                                            "altr,socfpga-eth-mac-ecc";
                                reg = <0xff8c0000 0x100>;
                                altr,ecc-parent = <&gmac0>;
-                               interrupts = <4 4>,
-                                            <36 4>;
+                               interrupts = <4 4>;
                        };
 
                        emac0-tx-ecc@ff8c0400 {
-                               compatible = "altr,socfpga-eth-mac-ecc";
+                               compatible = "altr,socfpga-s10-eth-mac-ecc",
+                                            "altr,socfpga-eth-mac-ecc";
                                reg = <0xff8c0400 0x100>;
                                altr,ecc-parent = <&gmac0>;
-                               interrupts = <5 4>,
-                                            <37 4>;
+                               interrupts = <5 4>;
                        };
 
                };
index 1bcf9aea0cdfc36ef7f16d28c6bb2181be9de734..8816f74a22b4a8082804f72b2a168cf26d1e9506 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/ctype.h>
 #include <linux/delay.h>
 #include <linux/edac.h>
+#include <linux/firmware/intel/stratix10-smc.h>
 #include <linux/genalloc.h>
 #include <linux/interrupt.h>
 #include <linux/irqchip/chained_irq.h>
@@ -1361,8 +1362,19 @@ static const struct edac_device_prv_data a10_l2ecc_data = {
 
 #ifdef CONFIG_EDAC_ALTERA_ETHERNET
 
+static int __init socfpga_init_ethernet_ecc(struct altr_edac_device_dev *dev)
+{
+       int ret;
+
+       ret = altr_init_a10_ecc_device_type("altr,socfpga-eth-mac-ecc");
+       if (ret)
+               return ret;
+
+       return altr_check_ecc_deps(dev);
+}
+
 static const struct edac_device_prv_data a10_enetecc_data = {
-       .setup = altr_check_ecc_deps,
+       .setup = socfpga_init_ethernet_ecc,
        .ce_clear_mask = ALTR_A10_ECC_SERRPENA,
        .ue_clear_mask = ALTR_A10_ECC_DERRPENA,
        .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL,
@@ -1374,21 +1386,25 @@ static const struct edac_device_prv_data a10_enetecc_data = {
        .inject_fops = &altr_edac_a10_device_inject2_fops,
 };
 
-static int __init socfpga_init_ethernet_ecc(void)
-{
-       return altr_init_a10_ecc_device_type("altr,socfpga-eth-mac-ecc");
-}
-
-early_initcall(socfpga_init_ethernet_ecc);
-
 #endif /* CONFIG_EDAC_ALTERA_ETHERNET */
 
 /********************** NAND Device Functions **********************/
 
 #ifdef CONFIG_EDAC_ALTERA_NAND
 
+static int __init socfpga_init_nand_ecc(struct altr_edac_device_dev *device)
+{
+       int ret;
+
+       ret = altr_init_a10_ecc_device_type("altr,socfpga-nand-ecc");
+       if (ret)
+               return ret;
+
+       return altr_check_ecc_deps(device);
+}
+
 static const struct edac_device_prv_data a10_nandecc_data = {
-       .setup = altr_check_ecc_deps,
+       .setup = socfpga_init_nand_ecc,
        .ce_clear_mask = ALTR_A10_ECC_SERRPENA,
        .ue_clear_mask = ALTR_A10_ECC_DERRPENA,
        .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL,
@@ -1400,21 +1416,25 @@ static const struct edac_device_prv_data a10_nandecc_data = {
        .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 */
 
 /********************** DMA Device Functions **********************/
 
 #ifdef CONFIG_EDAC_ALTERA_DMA
 
+static int __init socfpga_init_dma_ecc(struct altr_edac_device_dev *device)
+{
+       int ret;
+
+       ret = altr_init_a10_ecc_device_type("altr,socfpga-dma-ecc");
+       if (ret)
+               return ret;
+
+       return altr_check_ecc_deps(device);
+}
+
 static const struct edac_device_prv_data a10_dmaecc_data = {
-       .setup = altr_check_ecc_deps,
+       .setup = socfpga_init_dma_ecc,
        .ce_clear_mask = ALTR_A10_ECC_SERRPENA,
        .ue_clear_mask = ALTR_A10_ECC_DERRPENA,
        .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL,
@@ -1426,21 +1446,25 @@ static const struct edac_device_prv_data a10_dmaecc_data = {
        .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 */
 
 /********************** USB Device Functions **********************/
 
 #ifdef CONFIG_EDAC_ALTERA_USB
 
+static int __init socfpga_init_usb_ecc(struct altr_edac_device_dev *device)
+{
+       int ret;
+
+       ret = altr_init_a10_ecc_device_type("altr,socfpga-usb-ecc");
+       if (ret)
+               return ret;
+
+       return altr_check_ecc_deps(device);
+}
+
 static const struct edac_device_prv_data a10_usbecc_data = {
-       .setup = altr_check_ecc_deps,
+       .setup = socfpga_init_usb_ecc,
        .ce_clear_mask = ALTR_A10_ECC_SERRPENA,
        .ue_clear_mask = ALTR_A10_ECC_DERRPENA,
        .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL,
@@ -1452,21 +1476,25 @@ static const struct edac_device_prv_data a10_usbecc_data = {
        .inject_fops = &altr_edac_a10_device_inject2_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 */
 
 /********************** QSPI Device Functions **********************/
 
 #ifdef CONFIG_EDAC_ALTERA_QSPI
 
+static int __init socfpga_init_qspi_ecc(struct altr_edac_device_dev *device)
+{
+       int ret;
+
+       ret = altr_init_a10_ecc_device_type("altr,socfpga-qspi-ecc");
+       if (ret)
+               return ret;
+
+       return altr_check_ecc_deps(device);
+}
+
 static const struct edac_device_prv_data a10_qspiecc_data = {
-       .setup = altr_check_ecc_deps,
+       .setup = socfpga_init_qspi_ecc,
        .ce_clear_mask = ALTR_A10_ECC_SERRPENA,
        .ue_clear_mask = ALTR_A10_ECC_DERRPENA,
        .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL,
@@ -1478,13 +1506,6 @@ static const struct edac_device_prv_data a10_qspiecc_data = {
        .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 */
 
 /********************* SDMMC Device Functions **********************/
@@ -1593,6 +1614,35 @@ err_release_group_1:
        return rc;
 }
 
+static int __init socfpga_init_sdmmc_ecc(struct altr_edac_device_dev *device)
+{
+       int rc = -ENODEV;
+       struct device_node *child;
+
+       child = of_find_compatible_node(NULL, NULL, "altr,socfpga-sdmmc-ecc");
+       if (!child)
+               return -ENODEV;
+
+       if (!of_device_is_available(child))
+               goto exit;
+
+       if (validate_parent_available(child))
+               goto exit;
+
+       /* Init portB */
+       rc = altr_init_a10_ecc_block(child, ALTR_A10_SDMMC_IRQ_MASK,
+                                    a10_sdmmceccb_data.ecc_enable_mask, 1);
+       if (rc)
+               goto exit;
+
+       /* Setup portB */
+       return altr_portb_setup(device);
+
+exit:
+       of_node_put(child);
+       return rc;
+}
+
 static irqreturn_t altr_edac_a10_ecc_irq_portb(int irq, void *dev_id)
 {
        struct altr_edac_device_dev *ad = dev_id;
@@ -1617,7 +1667,7 @@ static irqreturn_t altr_edac_a10_ecc_irq_portb(int irq, void *dev_id)
 }
 
 static const struct edac_device_prv_data a10_sdmmcecca_data = {
-       .setup = altr_portb_setup,
+       .setup = socfpga_init_sdmmc_ecc,
        .ce_clear_mask = ALTR_A10_ECC_SERRPENA,
        .ue_clear_mask = ALTR_A10_ECC_DERRPENA,
        .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL,
@@ -1630,7 +1680,7 @@ static const struct edac_device_prv_data a10_sdmmcecca_data = {
 };
 
 static const struct edac_device_prv_data a10_sdmmceccb_data = {
-       .setup = altr_portb_setup,
+       .setup = socfpga_init_sdmmc_ecc,
        .ce_clear_mask = ALTR_A10_ECC_SERRPENB,
        .ue_clear_mask = ALTR_A10_ECC_DERRPENB,
        .ecc_enable_mask = ALTR_A10_COMMON_ECC_EN_CTL,
@@ -1642,35 +1692,6 @@ static const struct edac_device_prv_data a10_sdmmceccb_data = {
        .inject_fops = &altr_edac_a10_device_inject_fops,
 };
 
-static int __init socfpga_init_sdmmc_ecc(void)
-{
-       int rc = -ENODEV;
-       struct device_node *child;
-
-       if (!socfpga_is_a10() && !socfpga_is_s10())
-               return -ENODEV;
-
-       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 *************************/
@@ -1762,28 +1783,24 @@ static ssize_t altr_edac_a10_device_trig2(struct file *file,
        if (trig_type == ALTR_UE_TRIGGER_CHAR) {
                writel(priv->ue_set_mask, set_addr);
        } else {
-               /* Setup write of 0 to first 4 bytes */
-               writel(0x0, drvdata->base + ECC_BLK_WDATA0_OFST);
-               writel(0x0, drvdata->base + ECC_BLK_WDATA1_OFST);
-               writel(0x0, drvdata->base + ECC_BLK_WDATA2_OFST);
-               writel(0x0, drvdata->base + ECC_BLK_WDATA3_OFST);
-               /* Setup write of 4 bytes */
+               /* Setup read/write of 4 bytes */
                writel(ECC_WORD_WRITE, drvdata->base + ECC_BLK_DBYTECTRL_OFST);
                /* Setup Address to 0 */
-               writel(0x0, drvdata->base + ECC_BLK_ADDRESS_OFST);
-               /* Setup accctrl to write & data override */
-               writel(ECC_WRITE_DOVR, drvdata->base + ECC_BLK_ACCCTRL_OFST);
-               /* Kick it. */
-               writel(ECC_XACT_KICK, drvdata->base + ECC_BLK_STARTACC_OFST);
-               /* Setup accctrl to read & ecc override */
-               writel(ECC_READ_EOVR, drvdata->base + ECC_BLK_ACCCTRL_OFST);
+               writel(0, drvdata->base + ECC_BLK_ADDRESS_OFST);
+               /* Setup accctrl to read & ecc & data override */
+               writel(ECC_READ_EDOVR, drvdata->base + ECC_BLK_ACCCTRL_OFST);
                /* Kick it. */
                writel(ECC_XACT_KICK, drvdata->base + ECC_BLK_STARTACC_OFST);
                /* Setup write for single bit change */
-               writel(0x1, drvdata->base + ECC_BLK_WDATA0_OFST);
-               writel(0x0, drvdata->base + ECC_BLK_WDATA1_OFST);
-               writel(0x0, drvdata->base + ECC_BLK_WDATA2_OFST);
-               writel(0x0, drvdata->base + ECC_BLK_WDATA3_OFST);
+               writel(readl(drvdata->base + ECC_BLK_RDATA0_OFST) ^ 0x1,
+                      drvdata->base + ECC_BLK_WDATA0_OFST);
+               writel(readl(drvdata->base + ECC_BLK_RDATA1_OFST),
+                      drvdata->base + ECC_BLK_WDATA1_OFST);
+               writel(readl(drvdata->base + ECC_BLK_RDATA2_OFST),
+                      drvdata->base + ECC_BLK_WDATA2_OFST);
+               writel(readl(drvdata->base + ECC_BLK_RDATA3_OFST),
+                      drvdata->base + ECC_BLK_WDATA3_OFST);
+
                /* Copy Read ECC to Write ECC */
                writel(readl(drvdata->base + ECC_BLK_RECC0_OFST),
                       drvdata->base + ECC_BLK_WECC0_OFST);
@@ -1930,6 +1947,15 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac,
                goto err_release_group1;
        }
 
+#ifdef CONFIG_ARCH_STRATIX10
+       /* Use IRQ to determine SError origin instead of assigning IRQ */
+       rc = of_property_read_u32_index(np, "interrupts", 0, &altdev->db_irq);
+       if (rc) {
+               edac_printk(KERN_ERR, EDAC_DEVICE,
+                           "Unable to parse DB IRQ index\n");
+               goto err_release_group1;
+       }
+#else
        altdev->db_irq = irq_of_parse_and_map(np, 1);
        if (!altdev->db_irq) {
                edac_printk(KERN_ERR, EDAC_DEVICE, "Error allocating DBIRQ\n");
@@ -1943,6 +1969,7 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac,
                edac_printk(KERN_ERR, EDAC_DEVICE, "No DBERR IRQ resource\n");
                goto err_release_group1;
        }
+#endif
 
        rc = edac_device_add_device(dci);
        if (rc) {
@@ -2005,6 +2032,10 @@ static const struct irq_domain_ops a10_eccmgr_ic_ops = {
 /************** Stratix 10 EDAC Double Bit Error Handler ************/
 #define to_a10edac(p, m) container_of(p, struct altr_arria10_edac, m)
 
+#ifdef CONFIG_ARCH_STRATIX10
+/* panic routine issues reboot on non-zero panic_timeout */
+extern int panic_timeout;
+
 /*
  * The double bit error is handled through SError which is fatal. This is
  * called as a panic notifier to printout ECC error info as part of the panic.
@@ -2018,17 +2049,37 @@ static int s10_edac_dberr_handler(struct notifier_block *this,
        regmap_read(edac->ecc_mgr_map, S10_SYSMGR_ECC_INTSTAT_DERR_OFST,
                    &dberror);
        regmap_write(edac->ecc_mgr_map, S10_SYSMGR_UE_VAL_OFST, dberror);
-       if (dberror & S10_DDR0_IRQ_MASK) {
-               regmap_read(edac->ecc_mgr_map, A10_DERRADDR_OFST, &err_addr);
-               regmap_write(edac->ecc_mgr_map, S10_SYSMGR_UE_ADDR_OFST,
-                            err_addr);
-               edac_printk(KERN_ERR, EDAC_MC,
-                           "EDAC: [Uncorrectable errors @ 0x%08X]\n\n",
-                           err_addr);
+       if (dberror & S10_DBE_IRQ_MASK) {
+               struct list_head *position;
+               struct altr_edac_device_dev *ed;
+               struct arm_smccc_res result;
+
+               /* Find the matching DBE in the list of devices */
+               list_for_each(position, &edac->a10_ecc_devices) {
+                       ed = list_entry(position, struct altr_edac_device_dev,
+                                       next);
+                       if (!(BIT(ed->db_irq) & dberror))
+                               continue;
+
+                       writel(ALTR_A10_ECC_DERRPENA,
+                              ed->base + ALTR_A10_ECC_INTSTAT_OFST);
+                       err_addr = readl(ed->base + ALTR_S10_DERR_ADDRA_OFST);
+                       regmap_write(edac->ecc_mgr_map,
+                                    S10_SYSMGR_UE_ADDR_OFST, err_addr);
+                       edac_printk(KERN_ERR, EDAC_DEVICE,
+                                   "EDAC: [Fatal DBE on %s @ 0x%08X]\n",
+                                   ed->edac_dev_name, err_addr);
+                       break;
+               }
+               /* Notify the System through SMC. Reboot delay = 1 second */
+               panic_timeout = 1;
+               arm_smccc_smc(INTEL_SIP_SMC_ECC_DBE, dberror, 0, 0, 0, 0,
+                             0, 0, &result);
        }
 
        return NOTIFY_DONE;
 }
+#endif
 
 /****************** Arria 10 EDAC Probe Function *********************/
 static int altr_edac_a10_probe(struct platform_device *pdev)
@@ -2098,16 +2149,8 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
                                         altr_edac_a10_irq_handler,
                                         edac);
 
-       if (socfpga_is_a10()) {
-               edac->db_irq = platform_get_irq(pdev, 1);
-               if (edac->db_irq < 0) {
-                       dev_err(&pdev->dev, "No DBERR IRQ resource\n");
-                       return edac->db_irq;
-               }
-               irq_set_chained_handler_and_data(edac->db_irq,
-                                                altr_edac_a10_irq_handler,
-                                                edac);
-       } else {
+#ifdef CONFIG_ARCH_STRATIX10
+       {
                int dberror, err_addr;
 
                edac->panic_notifier.notifier_call = s10_edac_dberr_handler;
@@ -2130,6 +2173,15 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
                                     S10_SYSMGR_UE_ADDR_OFST, 0);
                }
        }
+#else
+       edac->db_irq = platform_get_irq(pdev, 1);
+       if (edac->db_irq < 0) {
+               dev_err(&pdev->dev, "No DBERR IRQ resource\n");
+               return edac->db_irq;
+       }
+       irq_set_chained_handler_and_data(edac->db_irq,
+                                        altr_edac_a10_irq_handler, edac);
+#endif
 
        for_each_child_of_node(pdev->dev.of_node, child) {
                if (!of_device_is_available(child))
index f8664bac9fa82bae6d1bf7be616c3a3a83b562bb..55654cc4bcdf35373517dd2c95d2af109d47de28 100644 (file)
@@ -289,6 +289,7 @@ struct altr_sdram_mc_data {
 #define ALTR_A10_ECC_INIT_WATCHDOG_10US      10000
 
 /************* Stratix10 Defines **************/
+#define ALTR_S10_DERR_ADDRA_OFST          0x2C
 
 /* Stratix10 ECC Manager Defines */
 #define S10_SYSMGR_ECC_INTMASK_CLR_OFST   0x98
@@ -299,6 +300,7 @@ struct altr_sdram_mc_data {
 #define S10_SYSMGR_UE_ADDR_OFST           0x224
 
 #define S10_DDR0_IRQ_MASK                 BIT(16)
+#define S10_DBE_IRQ_MASK                  0x3FE
 
 /* Define ECC Block Offsets for peripherals */
 #define ECC_BLK_ADDRESS_OFST              0x40
@@ -319,7 +321,7 @@ struct altr_sdram_mc_data {
 #define ECC_BLK_STARTACC_OFST             0x7C
 
 #define ECC_XACT_KICK                     0x10000
-#define ECC_WORD_WRITE                    0xF
+#define ECC_WORD_WRITE                    0xFF
 #define ECC_WRITE_DOVR                    0x101
 #define ECC_WRITE_EDOVR                   0x103
 #define ECC_READ_EOVR                     0x2
@@ -370,69 +372,4 @@ struct altr_arria10_edac {
        struct notifier_block   panic_notifier;
 };
 
-/*
- * Functions specified by ARM SMC Calling convention:
- *
- * FAST call executes atomic operations, returns when the requested operation
- * has completed.
- * STD call starts a operation which can be preempted by a non-secure
- * interrupt. The call can return before the requested operation has
- * completed.
- *
- * a0..a7 is used as register names in the descriptions below, on arm32
- * that translates to r0..r7 and on arm64 to w0..w7.
- */
-
-#define INTEL_SIP_SMC_STD_CALL_VAL(func_num) \
-       ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, ARM_SMCCC_SMC_64, \
-       ARM_SMCCC_OWNER_SIP, (func_num))
-
-#define INTEL_SIP_SMC_FAST_CALL_VAL(func_num) \
-       ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64, \
-       ARM_SMCCC_OWNER_SIP, (func_num))
-
-#define INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION          0xFFFFFFFF
-#define INTEL_SIP_SMC_STATUS_OK                                0x0
-#define INTEL_SIP_SMC_REG_ERROR                                0x5
-
-/*
- * Request INTEL_SIP_SMC_REG_READ
- *
- * Read a protected register using SMCCC
- *
- * Call register usage:
- * a0: INTEL_SIP_SMC_REG_READ.
- * a1: register address.
- * a2-7: not used.
- *
- * Return status:
- * a0: INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_REG_ERROR, or
- *     INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION
- * a1: Value in the register
- * a2-3: not used.
- */
-#define INTEL_SIP_SMC_FUNCID_REG_READ 7
-#define INTEL_SIP_SMC_REG_READ \
-       INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_REG_READ)
-
-/*
- * Request INTEL_SIP_SMC_REG_WRITE
- *
- * Write a protected register using SMCCC
- *
- * Call register usage:
- * a0: INTEL_SIP_SMC_REG_WRITE.
- * a1: register address
- * a2: value to program into register.
- * a3-7: not used.
- *
- * Return status:
- * a0: INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_REG_ERROR, or
- *     INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION
- * a1-3: not used.
- */
-#define INTEL_SIP_SMC_FUNCID_REG_WRITE 8
-#define INTEL_SIP_SMC_REG_WRITE \
-       INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_REG_WRITE)
-
 #endif /* #ifndef _ALTERA_EDAC_H */
index 6ea98575a402eece9cad74f63057b0b6dd1d8968..e2a99466faaa8c785dca39516a2e3917f309efb0 100644 (file)
@@ -18,6 +18,9 @@ static struct msr __percpu *msrs;
 /* Per-node stuff */
 static struct ecc_settings **ecc_stngs;
 
+/* Number of Unified Memory Controllers */
+static u8 num_umcs;
+
 /*
  * Valid scrub rates for the K8 hardware memory scrubber. We map the scrubbing
  * bandwidth to a valid bit pattern. The 'set' operation finds the 'matching-
@@ -449,6 +452,9 @@ static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct,
 #define for_each_chip_select_mask(i, dct, pvt) \
        for (i = 0; i < pvt->csels[dct].m_cnt; i++)
 
+#define for_each_umc(i) \
+       for (i = 0; i < num_umcs; i++)
+
 /*
  * @input_addr is an InputAddr associated with the node given by mci. Return the
  * csrow that input_addr maps to, or -1 on failure (no csrow claims input_addr).
@@ -722,7 +728,7 @@ static unsigned long determine_edac_cap(struct amd64_pvt *pvt)
        if (pvt->umc) {
                u8 i, umc_en_mask = 0, dimm_ecc_en_mask = 0;
 
-               for (i = 0; i < NUM_UMCS; i++) {
+               for_each_umc(i) {
                        if (!(pvt->umc[i].sdp_ctrl & UMC_SDP_INIT))
                                continue;
 
@@ -781,6 +787,22 @@ static void debug_dump_dramcfg_low(struct amd64_pvt *pvt, u32 dclr, int chan)
                 (dclr & BIT(15)) ?  "yes" : "no");
 }
 
+/*
+ * The Address Mask should be a contiguous set of bits in the non-interleaved
+ * case. So to check for CS interleaving, find the most- and least-significant
+ * bits of the mask, generate a contiguous bitmask, and compare the two.
+ */
+static bool f17_cs_interleaved(struct amd64_pvt *pvt, u8 ctrl, int cs)
+{
+       u32 mask = pvt->csels[ctrl].csmasks[cs >> 1];
+       u32 msb = fls(mask) - 1, lsb = ffs(mask) - 1;
+       u32 test_mask = GENMASK(msb, lsb);
+
+       edac_dbg(1, "mask=0x%08x test_mask=0x%08x\n", mask, test_mask);
+
+       return mask ^ test_mask;
+}
+
 static void debug_display_dimm_sizes_df(struct amd64_pvt *pvt, u8 ctrl)
 {
        int dimm, size0, size1, cs0, cs1;
@@ -797,8 +819,19 @@ static void debug_display_dimm_sizes_df(struct amd64_pvt *pvt, u8 ctrl)
                size1 = 0;
                cs1 = dimm * 2 + 1;
 
-               if (csrow_enabled(cs1, ctrl, pvt))
-                       size1 = pvt->ops->dbam_to_cs(pvt, ctrl, 0, cs1);
+               if (csrow_enabled(cs1, ctrl, pvt)) {
+                       /*
+                        * CS interleaving is only supported if both CSes have
+                        * the same amount of memory. Because they are
+                        * interleaved, it will look like both CSes have the
+                        * full amount of memory. Save the size for both as
+                        * half the amount we found on CS0, if interleaved.
+                        */
+                       if (f17_cs_interleaved(pvt, ctrl, cs1))
+                               size1 = size0 = (size0 >> 1);
+                       else
+                               size1 = pvt->ops->dbam_to_cs(pvt, ctrl, 0, cs1);
+               }
 
                amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n",
                                cs0,    size0,
@@ -811,7 +844,7 @@ static void __dump_misc_regs_df(struct amd64_pvt *pvt)
        struct amd64_umc *umc;
        u32 i, tmp, umc_base;
 
-       for (i = 0; i < NUM_UMCS; i++) {
+       for_each_umc(i) {
                umc_base = get_umc_base(i);
                umc = &pvt->umc[i];
 
@@ -894,8 +927,7 @@ static void dump_misc_regs(struct amd64_pvt *pvt)
 
        edac_dbg(1, "  DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no");
 
-       amd64_info("using %s syndromes.\n",
-                       ((pvt->ecc_sym_sz == 8) ? "x8" : "x4"));
+       amd64_info("using x%u syndromes.\n", pvt->ecc_sym_sz);
 }
 
 /*
@@ -1388,7 +1420,7 @@ static int f17_early_channel_count(struct amd64_pvt *pvt)
        int i, channels = 0;
 
        /* SDP Control bit 31 (SdpInit) is clear for unused UMC channels */
-       for (i = 0; i < NUM_UMCS; i++)
+       for_each_umc(i)
                channels += !!(pvt->umc[i].sdp_ctrl & UMC_SDP_INIT);
 
        amd64_info("MCT channel count: %d\n", channels);
@@ -2211,6 +2243,15 @@ static struct amd64_family_type family_types[] = {
                        .dbam_to_cs             = f17_base_addr_to_cs_size,
                }
        },
+       [F17_M30H_CPUS] = {
+               .ctl_name = "F17h_M30h",
+               .f0_id = PCI_DEVICE_ID_AMD_17H_M30H_DF_F0,
+               .f6_id = PCI_DEVICE_ID_AMD_17H_M30H_DF_F6,
+               .ops = {
+                       .early_channel_count    = f17_early_channel_count,
+                       .dbam_to_cs             = f17_base_addr_to_cs_size,
+               }
+       },
 };
 
 /*
@@ -2464,18 +2505,14 @@ static inline void decode_bus_error(int node_id, struct mce *m)
  * To find the UMC channel represented by this bank we need to match on its
  * instance_id. The instance_id of a bank is held in the lower 32 bits of its
  * IPID.
+ *
+ * Currently, we can derive the channel number by looking at the 6th nibble in
+ * the instance_id. For example, instance_id=0xYXXXXX where Y is the channel
+ * number.
  */
-static int find_umc_channel(struct amd64_pvt *pvt, struct mce *m)
+static int find_umc_channel(struct mce *m)
 {
-       u32 umc_instance_id[] = {0x50f00, 0x150f00};
-       u32 instance_id = m->ipid & GENMASK(31, 0);
-       int i, channel = -1;
-
-       for (i = 0; i < ARRAY_SIZE(umc_instance_id); i++)
-               if (umc_instance_id[i] == instance_id)
-                       channel = i;
-
-       return channel;
+       return (m->ipid & GENMASK(31, 0)) >> 20;
 }
 
 static void decode_umc_error(int node_id, struct mce *m)
@@ -2497,11 +2534,7 @@ static void decode_umc_error(int node_id, struct mce *m)
        if (m->status & MCI_STATUS_DEFERRED)
                ecc_type = 3;
 
-       err.channel = find_umc_channel(pvt, m);
-       if (err.channel < 0) {
-               err.err_code = ERR_CHANNEL;
-               goto log_error;
-       }
+       err.channel = find_umc_channel(m);
 
        if (umc_normaddr_to_sysaddr(m->addr, pvt->mc_node_id, err.channel, &sys_addr)) {
                err.err_code = ERR_NORM_ADDR;
@@ -2603,19 +2636,19 @@ static void determine_ecc_sym_sz(struct amd64_pvt *pvt)
        if (pvt->umc) {
                u8 i;
 
-               for (i = 0; i < NUM_UMCS; i++) {
+               for_each_umc(i) {
                        /* Check enabled channels only: */
-                       if ((pvt->umc[i].sdp_ctrl & UMC_SDP_INIT) &&
-                           (pvt->umc[i].ecc_ctrl & BIT(7))) {
-                               pvt->ecc_sym_sz = 8;
-                               break;
+                       if (pvt->umc[i].sdp_ctrl & UMC_SDP_INIT) {
+                               if (pvt->umc[i].ecc_ctrl & BIT(9)) {
+                                       pvt->ecc_sym_sz = 16;
+                                       return;
+                               } else if (pvt->umc[i].ecc_ctrl & BIT(7)) {
+                                       pvt->ecc_sym_sz = 8;
+                                       return;
+                               }
                        }
                }
-
-               return;
-       }
-
-       if (pvt->fam >= 0x10) {
+       } else if (pvt->fam >= 0x10) {
                u32 tmp;
 
                amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp);
@@ -2639,7 +2672,7 @@ static void __read_mc_regs_df(struct amd64_pvt *pvt)
        u32 i, umc_base;
 
        /* Read registers from each UMC */
-       for (i = 0; i < NUM_UMCS; i++) {
+       for_each_umc(i) {
 
                umc_base = get_umc_base(i);
                umc = &pvt->umc[i];
@@ -3052,7 +3085,7 @@ static bool ecc_enabled(struct pci_dev *F3, u16 nid)
        if (boot_cpu_data.x86 >= 0x17) {
                u8 umc_en_mask = 0, ecc_en_mask = 0;
 
-               for (i = 0; i < NUM_UMCS; i++) {
+               for_each_umc(i) {
                        u32 base = get_umc_base(i);
 
                        /* Only check enabled UMCs. */
@@ -3105,7 +3138,7 @@ f17h_determine_edac_ctl_cap(struct mem_ctl_info *mci, struct amd64_pvt *pvt)
 {
        u8 i, ecc_en = 1, cpk_en = 1;
 
-       for (i = 0; i < NUM_UMCS; i++) {
+       for_each_umc(i) {
                if (pvt->umc[i].sdp_ctrl & UMC_SDP_INIT) {
                        ecc_en &= !!(pvt->umc[i].umc_cap_hi & UMC_ECC_ENABLED);
                        cpk_en &= !!(pvt->umc[i].umc_cap_hi & UMC_ECC_CHIPKILL_CAP);
@@ -3203,6 +3236,10 @@ static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt)
                        fam_type = &family_types[F17_M10H_CPUS];
                        pvt->ops = &family_types[F17_M10H_CPUS].ops;
                        break;
+               } else if (pvt->model >= 0x30 && pvt->model <= 0x3f) {
+                       fam_type = &family_types[F17_M30H_CPUS];
+                       pvt->ops = &family_types[F17_M30H_CPUS].ops;
+                       break;
                }
                /* fall through */
        case 0x18:
@@ -3236,6 +3273,22 @@ static const struct attribute_group *amd64_edac_attr_groups[] = {
        NULL
 };
 
+/* Set the number of Unified Memory Controllers in the system. */
+static void compute_num_umcs(void)
+{
+       u8 model = boot_cpu_data.x86_model;
+
+       if (boot_cpu_data.x86 < 0x17)
+               return;
+
+       if (model >= 0x30 && model <= 0x3f)
+               num_umcs = 8;
+       else
+               num_umcs = 2;
+
+       edac_dbg(1, "Number of UMCs: %x", num_umcs);
+}
+
 static int init_one_instance(unsigned int nid)
 {
        struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
@@ -3260,7 +3313,7 @@ static int init_one_instance(unsigned int nid)
                goto err_free;
 
        if (pvt->fam >= 0x17) {
-               pvt->umc = kcalloc(NUM_UMCS, sizeof(struct amd64_umc), GFP_KERNEL);
+               pvt->umc = kcalloc(num_umcs, sizeof(struct amd64_umc), GFP_KERNEL);
                if (!pvt->umc) {
                        ret = -ENOMEM;
                        goto err_free;
@@ -3299,8 +3352,14 @@ static int init_one_instance(unsigned int nid)
         * Always allocate two channels since we can have setups with DIMMs on
         * only one channel. Also, this simplifies handling later for the price
         * of a couple of KBs tops.
+        *
+        * On Fam17h+, the number of controllers may be greater than two. So set
+        * the size equal to the maximum number of UMCs.
         */
-       layers[1].size = 2;
+       if (pvt->fam >= 0x17)
+               layers[1].size = num_umcs;
+       else
+               layers[1].size = 2;
        layers[1].is_virt_csrow = false;
 
        mci = edac_mc_alloc(nid, ARRAY_SIZE(layers), layers, 0);
@@ -3481,6 +3540,8 @@ static int __init amd64_edac_init(void)
        if (!msrs)
                goto err_free;
 
+       compute_num_umcs();
+
        for (i = 0; i < amd_nb_num(); i++) {
                err = probe_one_instance(i);
                if (err) {
index 4242f8e39c18fef057f8ae096a097f02a7add378..8f66472f7adc221ee5e4e6787f35547c663b8930 100644 (file)
 #define PCI_DEVICE_ID_AMD_17H_DF_F6    0x1466
 #define PCI_DEVICE_ID_AMD_17H_M10H_DF_F0 0x15e8
 #define PCI_DEVICE_ID_AMD_17H_M10H_DF_F6 0x15ee
+#define PCI_DEVICE_ID_AMD_17H_M30H_DF_F0 0x1490
+#define PCI_DEVICE_ID_AMD_17H_M30H_DF_F6 0x1496
 
 /*
  * Function 1 - Address Map
 
 #define UMC_SDP_INIT                   BIT(31)
 
-#define NUM_UMCS                       2
-
 enum amd_families {
        K8_CPUS = 0,
        F10_CPUS,
@@ -284,6 +284,7 @@ enum amd_families {
        F16_M30H_CPUS,
        F17_CPUS,
        F17_M10H_CPUS,
+       F17_M30H_CPUS,
        NUM_FAMILIES,
 };
 
@@ -363,7 +364,7 @@ struct amd64_pvt {
        u32 dct_sel_hi;         /* DRAM Controller Select High */
        u32 online_spare;       /* On-Line spare Reg */
 
-       /* x4 or x8 syndromes in use */
+       /* x4, x8, or x16 syndromes in use */
        u8 ecc_sym_sz;
 
        /* place to store error injection parameters prior to issue */
@@ -396,8 +397,8 @@ struct err_info {
 
 static inline u32 get_umc_base(u8 channel)
 {
-       /* ch0: 0x50000, ch1: 0x150000 */
-       return 0x50000 + (!!channel << 20);
+       /* chY: 0xY50000 */
+       return 0x50000 + (channel << 20);
 }
 
 static inline u64 get_dram_base(struct amd64_pvt *pvt, u8 i)
index c334fb7c63df5ec3ba4ced0ade673763b0d48277..6f06aec4877c208f150e5b429079d6bfba6110e0 100644 (file)
@@ -181,6 +181,54 @@ static struct notifier_block i10nm_mce_dec = {
        .priority       = MCE_PRIO_EDAC,
 };
 
+#ifdef CONFIG_EDAC_DEBUG
+/*
+ * Debug feature.
+ * Exercise the address decode logic by writing an address to
+ * /sys/kernel/debug/edac/i10nm_test/addr.
+ */
+static struct dentry *i10nm_test;
+
+static int debugfs_u64_set(void *data, u64 val)
+{
+       struct mce m;
+
+       pr_warn_once("Fake error to 0x%llx injected via debugfs\n", val);
+
+       memset(&m, 0, sizeof(m));
+       /* ADDRV + MemRd + Unknown channel */
+       m.status = MCI_STATUS_ADDRV + 0x90;
+       /* One corrected error */
+       m.status |= BIT_ULL(MCI_STATUS_CEC_SHIFT);
+       m.addr = val;
+       skx_mce_check_error(NULL, 0, &m);
+
+       return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n");
+
+static void setup_i10nm_debug(void)
+{
+       i10nm_test = edac_debugfs_create_dir("i10nm_test");
+       if (!i10nm_test)
+               return;
+
+       if (!edac_debugfs_create_file("addr", 0200, i10nm_test,
+                                     NULL, &fops_u64_wo)) {
+               debugfs_remove(i10nm_test);
+               i10nm_test = NULL;
+       }
+}
+
+static void teardown_i10nm_debug(void)
+{
+       debugfs_remove_recursive(i10nm_test);
+}
+#else
+static inline void setup_i10nm_debug(void) {}
+static inline void teardown_i10nm_debug(void) {}
+#endif /*CONFIG_EDAC_DEBUG*/
+
 static int __init i10nm_init(void)
 {
        u8 mc = 0, src_id = 0, node_id = 0;
@@ -249,7 +297,7 @@ static int __init i10nm_init(void)
 
        opstate_init();
        mce_register_decode_chain(&i10nm_mce_dec);
-       setup_skx_debug("i10nm_test");
+       setup_i10nm_debug();
 
        i10nm_printk(KERN_INFO, "%s\n", I10NM_REVISION);
 
@@ -262,7 +310,7 @@ fail:
 static void __exit i10nm_exit(void)
 {
        edac_dbg(2, "\n");
-       teardown_skx_debug();
+       teardown_i10nm_debug();
        mce_unregister_decode_chain(&i10nm_mce_dec);
        skx_adxl_put();
        skx_remove();
index adae4c848ca1ed5f6eb3c90ee95051b398152b3e..a5c8fa3a249acef3422c29a2541a9acca0d56831 100644 (file)
@@ -540,6 +540,54 @@ static struct notifier_block skx_mce_dec = {
        .priority       = MCE_PRIO_EDAC,
 };
 
+#ifdef CONFIG_EDAC_DEBUG
+/*
+ * Debug feature.
+ * Exercise the address decode logic by writing an address to
+ * /sys/kernel/debug/edac/skx_test/addr.
+ */
+static struct dentry *skx_test;
+
+static int debugfs_u64_set(void *data, u64 val)
+{
+       struct mce m;
+
+       pr_warn_once("Fake error to 0x%llx injected via debugfs\n", val);
+
+       memset(&m, 0, sizeof(m));
+       /* ADDRV + MemRd + Unknown channel */
+       m.status = MCI_STATUS_ADDRV + 0x90;
+       /* One corrected error */
+       m.status |= BIT_ULL(MCI_STATUS_CEC_SHIFT);
+       m.addr = val;
+       skx_mce_check_error(NULL, 0, &m);
+
+       return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n");
+
+static void setup_skx_debug(void)
+{
+       skx_test = edac_debugfs_create_dir("skx_test");
+       if (!skx_test)
+               return;
+
+       if (!edac_debugfs_create_file("addr", 0200, skx_test,
+                                     NULL, &fops_u64_wo)) {
+               debugfs_remove(skx_test);
+               skx_test = NULL;
+       }
+}
+
+static void teardown_skx_debug(void)
+{
+       debugfs_remove_recursive(skx_test);
+}
+#else
+static inline void setup_skx_debug(void) {}
+static inline void teardown_skx_debug(void) {}
+#endif /*CONFIG_EDAC_DEBUG*/
+
 /*
  * skx_init:
  *     make sure we are running on the correct cpu model
@@ -619,7 +667,7 @@ static int __init skx_init(void)
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
 
-       setup_skx_debug("skx_test");
+       setup_skx_debug();
 
        mce_register_decode_chain(&skx_mce_dec);
 
index 0e96e7b5b0a78748cb3899731370a1f0cc875112..b0dddcfa9baa2cb23dde83697b8d63a1d81d41ff 100644 (file)
@@ -1,7 +1,15 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Common codes for both the skx_edac driver and Intel 10nm server EDAC driver.
- * Originally split out from the skx_edac driver.
+ *
+ * Shared code by both skx_edac and i10nm_edac. Originally split out
+ * from the skx_edac driver.
+ *
+ * This file is linked into both skx_edac and i10nm_edac drivers. In
+ * order to avoid link errors, this file must be like a pure library
+ * without including symbols and defines which would otherwise conflict,
+ * when linked once into a module and into a built-in object, at the
+ * same time. For example, __this_module symbol references when that
+ * file is being linked into a built-in object.
  *
  * Copyright (c) 2018, Intel Corporation.
  */
@@ -644,48 +652,3 @@ void skx_remove(void)
                kfree(d);
        }
 }
-
-#ifdef CONFIG_EDAC_DEBUG
-/*
- * Debug feature.
- * Exercise the address decode logic by writing an address to
- * /sys/kernel/debug/edac/dirname/addr.
- */
-static struct dentry *skx_test;
-
-static int debugfs_u64_set(void *data, u64 val)
-{
-       struct mce m;
-
-       pr_warn_once("Fake error to 0x%llx injected via debugfs\n", val);
-
-       memset(&m, 0, sizeof(m));
-       /* ADDRV + MemRd + Unknown channel */
-       m.status = MCI_STATUS_ADDRV + 0x90;
-       /* One corrected error */
-       m.status |= BIT_ULL(MCI_STATUS_CEC_SHIFT);
-       m.addr = val;
-       skx_mce_check_error(NULL, 0, &m);
-
-       return 0;
-}
-DEFINE_SIMPLE_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n");
-
-void setup_skx_debug(const char *dirname)
-{
-       skx_test = edac_debugfs_create_dir(dirname);
-       if (!skx_test)
-               return;
-
-       if (!edac_debugfs_create_file("addr", 0200, skx_test,
-                                     NULL, &fops_u64_wo)) {
-               debugfs_remove(skx_test);
-               skx_test = NULL;
-       }
-}
-
-void teardown_skx_debug(void)
-{
-       debugfs_remove_recursive(skx_test);
-}
-#endif /*CONFIG_EDAC_DEBUG*/
index d25374e34d4f9279910aa4893a3ff60fb1477b1c..d18fa98669af118329fb5db5def0228485d7e490 100644 (file)
@@ -141,12 +141,4 @@ int skx_mce_check_error(struct notifier_block *nb, unsigned long val,
 
 void skx_remove(void);
 
-#ifdef CONFIG_EDAC_DEBUG
-void setup_skx_debug(const char *dirname);
-void teardown_skx_debug(void);
-#else
-static inline void setup_skx_debug(const char *dirname) {}
-static inline void teardown_skx_debug(void) {}
-#endif /*CONFIG_EDAC_DEBUG*/
-
 #endif /* _SKX_COMM_EDAC_H */
index 5be5dab50b132b421de821f0e7f2434985ce34c2..01684d935580eb7963ceb8d5a096dd41770519e1 100644 (file)
@@ -309,4 +309,23 @@ INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_COMPLETED_WRITE)
 #define INTEL_SIP_SMC_FUNCID_RSU_UPDATE 12
 #define INTEL_SIP_SMC_RSU_UPDATE \
        INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_RSU_UPDATE)
+
+/*
+ * Request INTEL_SIP_SMC_ECC_DBE
+ *
+ * Sync call used by service driver at EL1 to alert EL3 that a Double
+ * Bit ECC error has occurred.
+ *
+ * Call register usage:
+ * a0 INTEL_SIP_SMC_ECC_DBE
+ * a1 SysManager Double Bit Error value
+ * a2-7 not used
+ *
+ * Return status
+ * a0 INTEL_SIP_SMC_STATUS_OK
+ */
+#define INTEL_SIP_SMC_FUNCID_ECC_DBE 13
+#define INTEL_SIP_SMC_ECC_DBE \
+       INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_ECC_DBE)
+
 #endif