Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 275b103a authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents 4dd2ab9a 8de9930a
Loading
Loading
Loading
Loading
+125 −10
Original line number Diff line number Diff line
@@ -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>;
		};
	};
+7 −1
Original line number Diff line number Diff line
@@ -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>
+13 −12
Original line number Diff line number Diff line
@@ -534,11 +534,12 @@
		};

		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;
@@ -546,31 +547,31 @@
			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>;
			};

		};
+157 −105
Original line number Diff line number Diff line
@@ -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 @@ static int altr_portb_setup(struct altr_edac_device_dev *device)
	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))
+3 −66
Original line number Diff line number Diff line
@@ -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 */
Loading