2016-04-12 22:08:23

by Thor Thayer

[permalink] [raw]
Subject: [PATCH] Add EDAC peripheral init functions & Ethernet EDAC.

This patch set adds the memory initialization functions for Altera's
Arria10 peripherals, the first of which is the Ethernet EDAC. The
first 3 patches add the memory initialization functionality. The
last 3 patches add Ethernet EDAC support.

[PATCH 1/6] EDAC, altera: Check parent status for Arria10 EDAC block
[PATCH 2/6] EDAC, altera: Move IRQ function declaration
[PATCH 3/6] EDAC, altera: Add Arria10 ECC memory init functions
[PATCH 4/6] Documentation: dt: socfpga: Add Arria10 Ethernet binding
[PATCH 5/6] EDAC, altera: Add Arria10 Ethernet EDAC support
[PATCH 6/6] ARM: dts: Add Arria10 Ethernet EDAC devicetree entry


2016-04-12 22:08:38

by Thor Thayer

[permalink] [raw]
Subject: [PATCH 1/6] EDAC, altera: Check parent status for Arria10 EDAC block

From: Thor Thayer <[email protected]>

In preparation for the Arria10 ECC modules, check the status
of the parent in the device tree to ensure the block is enabled.
Skip if no parent phandle is set in the device tree.

Signed-off-by: Thor Thayer <[email protected]>
---
drivers/edac/altera_edac.c | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
index 11775dc..c3e040d 100644
--- a/drivers/edac/altera_edac.c
+++ b/drivers/edac/altera_edac.c
@@ -1115,6 +1115,7 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac,
struct resource res;
int edac_idx;
int rc = 0;
+ struct device_node *parent;
const struct edac_device_prv_data *prv;
/* Get matching node and check for valid result */
const struct of_device_id *pdev_id =
@@ -1127,6 +1128,14 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac,
if (IS_ERR_OR_NULL(prv))
return -ENODEV;

+ /* If there is a parent parameter, exit if it is not available. */
+ parent = of_parse_phandle(np, "parent", 0);
+ if (parent && !of_device_is_available(parent)) {
+ of_node_put(parent);
+ return -ENODEV;
+ }
+ of_node_put(parent);
+
if (!devres_open_group(edac->dev, altr_edac_a10_device_add, GFP_KERNEL))
return -ENOMEM;

--
1.7.9.5

2016-04-12 22:08:49

by Thor Thayer

[permalink] [raw]
Subject: [PATCH 2/6] EDAC, altera: Move IRQ function declaration

From: Thor Thayer <[email protected]>

In preparation for additional memory module ECCs, the
IRQ declaration is being made available to everyone.
Move it outside of the OCRAM only area.

Signed-off-by: Thor Thayer <[email protected]>
---
drivers/edac/altera_edac.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
index c3e040d..226e650 100644
--- a/drivers/edac/altera_edac.c
+++ b/drivers/edac/altera_edac.c
@@ -848,6 +848,10 @@ static struct platform_driver altr_edac_device_driver = {
};
module_platform_driver(altr_edac_device_driver);

+/********************* Arria10 Function Declarations *********************/
+static irqreturn_t altr_edac_a10_ecc_irq(struct altr_edac_device_dev *dci,
+ bool sberr);
+
/*********************** OCRAM EDAC Device Functions *********************/

#ifdef CONFIG_EDAC_ALTERA_OCRAM
@@ -902,9 +906,6 @@ const struct edac_device_prv_data ocramecc_data = {
.inject_fops = &altr_edac_device_inject_fops,
};

-static irqreturn_t altr_edac_a10_ecc_irq(struct altr_edac_device_dev *dci,
- bool sberr);
-
const struct edac_device_prv_data a10_ocramecc_data = {
.setup = altr_check_ecc_deps,
.ce_clear_mask = ALTR_A10_ECC_SERRPENA,
--
1.7.9.5

2016-04-12 22:08:58

by Thor Thayer

[permalink] [raw]
Subject: [PATCH 6/6] ARM: dts: Add Arria10 Ethernet EDAC devicetree entry

From: Thor Thayer <[email protected]>

Add the device tree entries needed to support the Altera Ethernet
FIFO buffer EDAC on the Arria10 chip.

Signed-off-by: Thor Thayer <[email protected]>
---
arch/arm/boot/dts/socfpga_arria10.dtsi | 36 ++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)

diff --git a/arch/arm/boot/dts/socfpga_arria10.dtsi b/arch/arm/boot/dts/socfpga_arria10.dtsi
index 27cc497..6195ade 100644
--- a/arch/arm/boot/dts/socfpga_arria10.dtsi
+++ b/arch/arm/boot/dts/socfpga_arria10.dtsi
@@ -617,6 +617,42 @@
compatible = "altr,socfpga-a10-ocram-ecc";
reg = <0xff8c3000 0x400>;
};
+
+ emac0-rx-ecc@ff8c0800 {
+ compatible = "altr,socfpga-a10-emac0-rx-ecc";
+ reg = <0xff8c0800 0x400>;
+ parent = <&gmac0>;
+ };
+
+ emac0-tx-ecc@ff8c0c00 {
+ compatible = "altr,socfpga-a10-emac0-tx-ecc";
+ reg = <0xff8c0c00 0x400>;
+ parent = <&gmac0>;
+ };
+
+ emac1-rx-ecc@ff8c1000 {
+ compatible = "altr,socfpga-a10-emac1-rx-ecc";
+ reg = <0xff8c1000 0x400>;
+ parent = <&gmac1>;
+ };
+
+ emac1-tx-ecc@ff8c1400 {
+ compatible = "altr,socfpga-a10-emac1-tx-ecc";
+ reg = <0xff8c1400 0x400>;
+ parent = <&gmac1>;
+ };
+
+ emac2-rx-ecc@ff8c1800 {
+ compatible = "altr,socfpga-a10-emac2-rx-ecc";
+ reg = <0xff8c1800 0x400>;
+ parent = <&gmac2>;
+ };
+
+ emac2-tx-ecc@ff8c1c00 {
+ compatible = "altr,socfpga-a10-emac2-tx-ecc";
+ reg = <0xff8c1c00 0x400>;
+ parent = <&gmac2>;
+ };
};

rst: rstmgr@ffd05000 {
--
1.7.9.5

2016-04-12 22:09:11

by Thor Thayer

[permalink] [raw]
Subject: [PATCH 5/6] EDAC, altera: Add Arria10 Ethernet EDAC support

From: Thor Thayer <[email protected]>

Add Altera Arria10 Ethernet FIFO memory EDAC support.

Signed-off-by: Thor Thayer <[email protected]>
---
drivers/edac/Kconfig | 7 ++
drivers/edac/altera_edac.c | 153 ++++++++++++++++++++++++++++++++++++++++++++
drivers/edac/altera_edac.h | 14 ++++
3 files changed, 174 insertions(+)

diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 6ca7474..d0c1dab 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -391,6 +391,13 @@ config EDAC_ALTERA_OCRAM
Support for error detection and correction on the
Altera On-Chip RAM Memory for Altera SoCs.

+config EDAC_ALTERA_ETHERNET
+ bool "Altera Ethernet FIFO ECC"
+ depends on EDAC_ALTERA=y
+ help
+ Support for error detection and correction on the
+ Altera Ethernet 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 0955ab0..43b6f36 100644
--- a/drivers/edac/altera_edac.c
+++ b/drivers/edac/altera_edac.c
@@ -553,6 +553,12 @@ const struct edac_device_prv_data ocramecc_data;
const struct edac_device_prv_data l2ecc_data;
const struct edac_device_prv_data a10_ocramecc_data;
const struct edac_device_prv_data a10_l2ecc_data;
+const struct edac_device_prv_data a10_enet0rxecc_data;
+const struct edac_device_prv_data a10_enet0txecc_data;
+const struct edac_device_prv_data a10_enet1rxecc_data;
+const struct edac_device_prv_data a10_enet1txecc_data;
+const struct edac_device_prv_data a10_enet2rxecc_data;
+const struct edac_device_prv_data a10_enet2txecc_data;

static irqreturn_t altr_edac_device_handler(int irq, void *dev_id)
{
@@ -716,6 +722,20 @@ static const struct of_device_id altr_edac_device_of_match[] = {
{ .compatible = "altr,socfpga-a10-ocram-ecc",
.data = (void *)&a10_ocramecc_data },
#endif
+#ifdef CONFIG_EDAC_ALTERA_ETHERNET
+ { .compatible = "altr,socfpga-a10-emac0-rx-ecc",
+ .data = (void *)&a10_enet0rxecc_data },
+ { .compatible = "altr,socfpga-a10-emac0-tx-ecc",
+ .data = (void *)&a10_enet0txecc_data },
+ { .compatible = "altr,socfpga-a10-emac1-rx-ecc",
+ .data = (void *)&a10_enet1rxecc_data },
+ { .compatible = "altr,socfpga-a10-emac1-tx-ecc",
+ .data = (void *)&a10_enet1txecc_data },
+ { .compatible = "altr,socfpga-a10-emac2-rx-ecc",
+ .data = (void *)&a10_enet2rxecc_data },
+ { .compatible = "altr,socfpga-a10-emac2-tx-ecc",
+ .data = (void *)&a10_enet2txecc_data },
+#endif
{},
};
MODULE_DEVICE_TABLE(of, altr_edac_device_of_match);
@@ -1033,6 +1053,126 @@ const struct edac_device_prv_data a10_l2ecc_data = {

#endif /* CONFIG_EDAC_ALTERA_L2C */

+/********************* Ethernet Device Functions ********************/
+
+#ifdef CONFIG_EDAC_ALTERA_ETHERNET
+
+const struct edac_device_prv_data a10_enet0rxecc_data = {
+ .setup = altr_check_ecc_deps,
+ .ce_clear_mask = ALTR_A10_ECC_SERRPENA,
+ .ue_clear_mask = ALTR_A10_ECC_DERRPENA,
+ .irq_status_mask = A10_SYSMGR_ECC_INTSTAT_EMAC0RX,
+ .dbgfs_name = "altr_emac0rx_trigger",
+ .ecc_enable_mask = ALTR_A10_ETHERNET_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,
+};
+
+const struct edac_device_prv_data a10_enet0txecc_data = {
+ .setup = altr_check_ecc_deps,
+ .ce_clear_mask = ALTR_A10_ECC_SERRPENA,
+ .ue_clear_mask = ALTR_A10_ECC_DERRPENA,
+ .irq_status_mask = A10_SYSMGR_ECC_INTSTAT_EMAC0TX,
+ .dbgfs_name = "altr_emac0tx_trigger",
+ .ecc_enable_mask = ALTR_A10_ETHERNET_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,
+};
+
+const struct edac_device_prv_data a10_enet1rxecc_data = {
+ .setup = altr_check_ecc_deps,
+ .ce_clear_mask = ALTR_A10_ECC_SERRPENA,
+ .ue_clear_mask = ALTR_A10_ECC_DERRPENA,
+ .irq_status_mask = A10_SYSMGR_ECC_INTSTAT_EMAC1RX,
+ .dbgfs_name = "altr_emac1rx_trigger",
+ .ecc_enable_mask = ALTR_A10_ETHERNET_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,
+};
+
+const struct edac_device_prv_data a10_enet1txecc_data = {
+ .setup = altr_check_ecc_deps,
+ .ce_clear_mask = ALTR_A10_ECC_SERRPENA,
+ .ue_clear_mask = ALTR_A10_ECC_DERRPENA,
+ .irq_status_mask = A10_SYSMGR_ECC_INTSTAT_EMAC1TX,
+ .dbgfs_name = "altr_emac1tx_trigger",
+ .ecc_enable_mask = ALTR_A10_ETHERNET_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,
+};
+
+const struct edac_device_prv_data a10_enet2rxecc_data = {
+ .setup = altr_check_ecc_deps,
+ .ce_clear_mask = ALTR_A10_ECC_SERRPENA,
+ .ue_clear_mask = ALTR_A10_ECC_DERRPENA,
+ .irq_status_mask = A10_SYSMGR_ECC_INTSTAT_EMAC2RX,
+ .dbgfs_name = "altr_emac2rx_trigger",
+ .ecc_enable_mask = ALTR_A10_ETHERNET_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,
+};
+
+const struct edac_device_prv_data a10_enet2txecc_data = {
+ .setup = altr_check_ecc_deps,
+ .ce_clear_mask = ALTR_A10_ECC_SERRPENA,
+ .ue_clear_mask = ALTR_A10_ECC_DERRPENA,
+ .irq_status_mask = A10_SYSMGR_ECC_INTSTAT_EMAC2TX,
+ .dbgfs_name = "altr_emac2tx_trigger",
+ .ecc_enable_mask = ALTR_A10_ETHERNET_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 const struct a10_ecc_init_vars a10_enet_ecc_init[] = {
+ {"altr,socfpga-a10-emac0-rx-ecc", A10_SYSMGR_ECC_INTSTAT_EMAC0RX},
+ {"altr,socfpga-a10-emac0-tx-ecc", A10_SYSMGR_ECC_INTSTAT_EMAC0TX},
+ {"altr,socfpga-a10-emac1-rx-ecc", A10_SYSMGR_ECC_INTSTAT_EMAC1RX},
+ {"altr,socfpga-a10-emac1-tx-ecc", A10_SYSMGR_ECC_INTSTAT_EMAC1TX},
+ {"altr,socfpga-a10-emac2-rx-ecc", A10_SYSMGR_ECC_INTSTAT_EMAC2RX},
+ {"altr,socfpga-a10-emac2-tx-ecc", A10_SYSMGR_ECC_INTSTAT_EMAC2TX},
+};
+
+static int __init socfpga_init_ethernet_ecc(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(a10_enet_ecc_init); i++) {
+ altr_init_a10_ecc_block(a10_enet_ecc_init[i].ecc_str,
+ a10_enet_ecc_init[i].irq_mask,
+ ALTR_A10_ETHERNET_ECC_EN_CTL, 0);
+ }
+
+ return 0;
+}
+
+early_initcall(socfpga_init_ethernet_ecc);
+
+#endif /* CONFIG_EDAC_ALTERA_ETHERNET */
+
/********************* Arria10 EDAC Device Functions *************************/

/*
@@ -1411,6 +1551,19 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
else if (of_device_is_compatible(child,
"altr,socfpga-a10-ocram-ecc"))
altr_edac_a10_device_add(edac, child);
+ else if ((of_device_is_compatible(child,
+ "altr,socfpga-a10-emac0-rx-ecc")) ||
+ (of_device_is_compatible(child,
+ "altr,socfpga-a10-emac0-tx-ecc")) ||
+ (of_device_is_compatible(child,
+ "altr,socfpga-a10-emac1-rx-ecc")) ||
+ (of_device_is_compatible(child,
+ "altr,socfpga-a10-emac1-tx-ecc")) ||
+ (of_device_is_compatible(child,
+ "altr,socfpga-a10-emac2-rx-ecc")) ||
+ (of_device_is_compatible(child,
+ "altr,socfpga-a10-emac2-tx-ecc")))
+ altr_edac_a10_device_add(edac, child);
}

return 0;
diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h
index 7e66015..d2275b4 100644
--- a/drivers/edac/altera_edac.h
+++ b/drivers/edac/altera_edac.h
@@ -255,6 +255,12 @@ struct altr_sdram_mc_data {
#define A10_SYSMGR_ECC_INTSTAT_DERR_OFST 0xA0
#define A10_SYSMGR_ECC_INTSTAT_L2 BIT(0)
#define A10_SYSMGR_ECC_INTSTAT_OCRAM BIT(1)
+#define A10_SYSMGR_ECC_INTSTAT_EMAC0RX BIT(4)
+#define A10_SYSMGR_ECC_INTSTAT_EMAC0TX BIT(5)
+#define A10_SYSMGR_ECC_INTSTAT_EMAC1RX BIT(6)
+#define A10_SYSMGR_ECC_INTSTAT_EMAC1TX BIT(7)
+#define A10_SYSMGR_ECC_INTSTAT_EMAC2RX BIT(8)
+#define A10_SYSMGR_ECC_INTSTAT_EMAC2TX BIT(9)

#define A10_SYSGMR_MPU_CLEAR_L2_ECC_OFST 0xA8
#define A10_SYSGMR_MPU_CLEAR_L2_ECC_SB BIT(15)
@@ -280,6 +286,9 @@ struct altr_sdram_mc_data {
/* Arria 10 OCRAM ECC Management Group Defines */
#define ALTR_A10_OCRAM_ECC_EN_CTL (BIT(1) | BIT(0))

+/* Arria 10 Ethernet ECC Management Group Defines */
+#define ALTR_A10_ETHERNET_ECC_EN_CTL BIT(0)
+
/* A10 ECC Controller memory initialization timeout */
#define ALTR_A10_ECC_INIT_WATCHDOG_10US 10000

@@ -326,4 +335,9 @@ struct altr_arria10_edac {
struct list_head a10_ecc_devices;
};

+struct a10_ecc_init_vars {
+ u8 ecc_str[32];
+ u32 irq_mask;
+};
+
#endif /* #ifndef _ALTERA_EDAC_H */
--
1.7.9.5

2016-04-12 22:09:59

by Thor Thayer

[permalink] [raw]
Subject: [PATCH 4/6] Documentation: dt: socfpga: Add Arria10 Ethernet binding

From: Thor Thayer <[email protected]>

Add the device tree bindings needed to support the Altera Ethernet
FIFO buffers on the Arria10 chip.

Signed-off-by: Thor Thayer <[email protected]>
---
.../bindings/arm/altera/socfpga-eccmgr.txt | 24 ++++++++++++++++++++
1 file changed, 24 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt b/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt
index 5a6b160..aa1c593 100644
--- a/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt
+++ b/Documentation/devicetree/bindings/arm/altera/socfpga-eccmgr.txt
@@ -76,6 +76,18 @@ Required Properties:
- compatible : Should be "altr,socfpga-a10-ocram-ecc"
- reg : Address and size for ECC block registers.

+Ethernet FIFO ECC
+Required Properties:
+- compatible : Should be "altr,socfpga-a10-emac0-rx-ecc" for the 1st EMAC
+ Receive buffer
+ or "altr,socfpga-a10-emac0-tx-ecc" for the 1st EMAC Transmit buffer
+ or "altr,socfpga-a10-emac1-rx-ecc" for the 2nd EMAC Receive buffer
+ or "altr,socfpga-a10-emac1-tx-ecc" for the 2nd EMAC Transmit buffer
+ or "altr,socfpga-a10-emac2-rx-ecc" for the 3rd EMAC Receive buffer
+ or "altr,socfpga-a10-emac2-tx-ecc" for the 3rd EMAC Transmit buffer
+- reg : Address and size for ECC block registers.
+- parent : phandle to parent Ethernet node.
+
Example:

eccmgr: eccmgr@ffd06000 {
@@ -96,4 +108,16 @@ Example:
compatible = "altr,socfpga-a10-ocram-ecc";
reg = <0xff8c3000 0x90>;
};
+
+ emac0-rx-ecc@ff8c0800 {
+ compatible = "altr,socfpga-a10-emac0-rx-ecc";
+ reg = <0xff8c0800 0x400>;
+ parent = <&gmac0>;
+ };
+
+ emac0-tx-ecc@ff8c0c00 {
+ compatible = "altr,socfpga-a10-emac0-tx-ecc";
+ reg = <0xff8c0c00 0x400>;
+ parent = <&gmac0>;
+ };
};
--
1.7.9.5

2016-04-12 22:10:34

by Thor Thayer

[permalink] [raw]
Subject: [PATCH 3/6] EDAC, altera: Add Arria10 ECC memory init functions

From: Thor Thayer <[email protected]>

In preparation for additional memory module ECCs, add the
memory initialization functions.

Signed-off-by: Thor Thayer <[email protected]>
---
drivers/edac/altera_edac.c | 152 ++++++++++++++++++++++++++++++++++++++++++++
drivers/edac/altera_edac.h | 3 +
2 files changed, 155 insertions(+)

diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
index 226e650..0955ab0 100644
--- a/drivers/edac/altera_edac.c
+++ b/drivers/edac/altera_edac.c
@@ -19,6 +19,7 @@

#include <asm/cacheflush.h>
#include <linux/ctype.h>
+#include <linux/delay.h>
#include <linux/edac.h>
#include <linux/genalloc.h>
#include <linux/interrupt.h>
@@ -851,6 +852,8 @@ module_platform_driver(altr_edac_device_driver);
/********************* Arria10 Function Declarations *********************/
static irqreturn_t altr_edac_a10_ecc_irq(struct altr_edac_device_dev *dci,
bool sberr);
+static int altr_init_a10_ecc_block(const char *compat, u32 irq_mask,
+ u32 ecc_ctrl_en_mask, bool dual_port);

/*********************** OCRAM EDAC Device Functions *********************/

@@ -1039,6 +1042,155 @@ const struct edac_device_prv_data a10_l2ecc_data = {
* Based on xgene_edac.c peripheral code.
*/

+static inline void ecc_set_bits(u32 bit_mask, void __iomem *ioaddr)
+{
+ u32 value = readl(ioaddr);
+
+ value |= bit_mask;
+ writel(value, ioaddr);
+}
+
+static inline void ecc_clear_bits(u32 bit_mask, void __iomem *ioaddr)
+{
+ u32 value = readl(ioaddr);
+
+ value &= ~bit_mask;
+ writel(value, ioaddr);
+}
+
+static inline int ecc_test_bits(u32 bit_mask, void __iomem *ioaddr)
+{
+ u32 value = readl(ioaddr);
+
+ return (value & bit_mask) ? 1 : 0;
+}
+
+/*
+ * This function uses the memory initialization block in the Arria10 ECC
+ * controller to initialize/clear the entire memory data and ECC data.
+ */
+static int altr_init_memory_port(void __iomem *ioaddr, int port)
+{
+ int limit = ALTR_A10_ECC_INIT_WATCHDOG_10US;
+ u32 init_mask = ALTR_A10_ECC_INITA;
+ u32 stat_mask = ALTR_A10_ECC_INITCOMPLETEA;
+ u32 clear_mask = ALTR_A10_ECC_ERRPENA_MASK;
+ int ret = 0;
+
+ if (port) {
+ init_mask = ALTR_A10_ECC_INITB;
+ stat_mask = ALTR_A10_ECC_INITCOMPLETEB;
+ clear_mask = ALTR_A10_ECC_ERRPENB_MASK;
+ }
+
+ ecc_set_bits(init_mask, (ioaddr + ALTR_A10_ECC_CTRL_OFST));
+ while (limit--) {
+ if (ecc_test_bits(stat_mask,
+ (ioaddr + ALTR_A10_ECC_INITSTAT_OFST)))
+ break;
+ udelay(1);
+ }
+ if (limit < 0)
+ ret = -EBUSY;
+
+ /* Clear any pending ECC interrupts */
+ writel(clear_mask, (ioaddr + ALTR_A10_ECC_INTSTAT_OFST));
+
+ return ret;
+}
+
+/*
+ * Aside from the L2 ECC, the Arria10 ECC memories have a common register
+ * layout so the following functions can be shared between all peripherals.
+ */
+static int altr_init_a10_ecc_block(const char *compat, u32 irq_mask,
+ u32 ecc_ctrl_en_mask, bool dual_port)
+{
+ int ret = 0;
+ void __iomem *ecc_block_base;
+ struct regmap *ecc_mgr_map;
+ char *ecc_name;
+ struct device_node *np, *parent, *np_eccmgr;
+
+ np = of_find_compatible_node(NULL, NULL, compat);
+ if (!np) {
+ pr_err("SOCFPGA: Unable to find %s in dtb\n", compat);
+ ret = -ENODEV;
+ goto out;
+ }
+ ecc_name = (char *)np->name;
+
+ /* Ensure device is enabled before calling init, otherwise exit */
+ parent = of_parse_phandle(np, "parent", 0);
+ if (!parent || !of_device_is_available(parent)) {
+ ret = -ENODEV;
+ goto out1;
+ }
+
+ /* Get the ECC Manager - parent of the device EDACs */
+ np_eccmgr = of_get_parent(np);
+ ecc_mgr_map = syscon_regmap_lookup_by_phandle(np_eccmgr,
+ "altr,sysmgr-syscon");
+ of_node_put(np_eccmgr);
+ if (IS_ERR(ecc_mgr_map)) {
+ edac_printk(KERN_ERR, EDAC_DEVICE,
+ "Unable to get syscon altr,sysmgr-syscon\n");
+ ret = -ENODEV;
+ goto out1;
+ }
+
+ /* Map the ECC Block */
+ ecc_block_base = of_iomap(np, 0);
+ if (!ecc_block_base) {
+ edac_printk(KERN_ERR, EDAC_DEVICE,
+ "Unable to map %s ECC block\n", ecc_name);
+ ret = -ENODEV;
+ goto out1;
+ }
+
+ /* Disable ECC */
+ regmap_write(ecc_mgr_map, A10_SYSMGR_ECC_INTMASK_SET_OFST, irq_mask);
+ ecc_clear_bits(ALTR_A10_ECC_SERRINTEN,
+ (ecc_block_base + ALTR_A10_ECC_ERRINTEN_OFST));
+ ecc_clear_bits(ecc_ctrl_en_mask,
+ (ecc_block_base + ALTR_A10_ECC_CTRL_OFST));
+ /* Ensure all writes complete */
+ wmb();
+ /* Use HW initialization block to initialize memory for ECC */
+ ret = altr_init_memory_port(ecc_block_base, 0);
+ if (ret) {
+ edac_printk(KERN_ERR, EDAC_DEVICE,
+ "ECC: cannot init %s PORTA memory\n", ecc_name);
+ goto out2;
+ }
+
+ if (dual_port) {
+ ret = altr_init_memory_port(ecc_block_base, 1);
+ if (ret) {
+ edac_printk(KERN_ERR, EDAC_DEVICE,
+ "ECC: cannot init %s PORTB memory\n",
+ ecc_name);
+ goto out2;
+ }
+ }
+
+ /* Enable ECC */
+ ecc_set_bits(ecc_ctrl_en_mask, (ecc_block_base +
+ ALTR_A10_ECC_CTRL_OFST));
+ ecc_set_bits(ALTR_A10_ECC_SERRINTEN,
+ (ecc_block_base + ALTR_A10_ECC_ERRINTEN_OFST));
+ regmap_write(ecc_mgr_map, A10_SYSMGR_ECC_INTMASK_CLR_OFST, irq_mask);
+ /* Ensure all writes complete */
+ wmb();
+out2:
+ iounmap(ecc_block_base);
+out1:
+ of_node_put(parent);
+out:
+ of_node_put(np);
+ return ret;
+}
+
static ssize_t altr_edac_a10_device_trig(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h
index 42090f3..7e66015 100644
--- a/drivers/edac/altera_edac.h
+++ b/drivers/edac/altera_edac.h
@@ -280,6 +280,9 @@ struct altr_sdram_mc_data {
/* Arria 10 OCRAM ECC Management Group Defines */
#define ALTR_A10_OCRAM_ECC_EN_CTL (BIT(1) | BIT(0))

+/* A10 ECC Controller memory initialization timeout */
+#define ALTR_A10_ECC_INIT_WATCHDOG_10US 10000
+
struct altr_edac_device_dev;

struct edac_device_prv_data {
--
1.7.9.5

2016-04-14 14:35:11

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH] Add EDAC peripheral init functions & Ethernet EDAC.

On Tue, Apr 12, 2016 at 05:12:55PM -0500, [email protected] wrote:
> This patch set adds the memory initialization functions for Altera's
> Arria10 peripherals, the first of which is the Ethernet EDAC. The
> first 3 patches add the memory initialization functionality. The
> last 3 patches add Ethernet EDAC support.

The ethernet part seems a bit strange to me to put under EDAC as EDAC
is primarily memory controller ECC (and caches to some extent). Also you
would not halt the system in case of an UC, but rather just drop the
frame. This would need to be part of the ethernet driver in that case.

Of course, given that ethernet frames already have a CRC, ECC of the
FIFO seems a bit redundant.

Rob

2016-04-15 09:51:05

by Mauro Carvalho Chehab

[permalink] [raw]
Subject: Re: [PATCH] Add EDAC peripheral init functions & Ethernet EDAC.

Em Thu, 14 Apr 2016 09:35:01 -0500
Rob Herring <[email protected]> escreveu:

> On Tue, Apr 12, 2016 at 05:12:55PM -0500, [email protected] wrote:
> > This patch set adds the memory initialization functions for Altera's
> > Arria10 peripherals, the first of which is the Ethernet EDAC. The
> > first 3 patches add the memory initialization functionality. The
> > last 3 patches add Ethernet EDAC support.
>
> The ethernet part seems a bit strange to me to put under EDAC as EDAC
> is primarily memory controller ECC (and caches to some extent). Also you
> would not halt the system in case of an UC, but rather just drop the
> frame. This would need to be part of the ethernet driver in that case.
>
> Of course, given that ethernet frames already have a CRC, ECC of the
> FIFO seems a bit redundant.

Actually, EDAC was conceived to be a way to report hardware errors, and,
although the main use case is for memory and CPU errors, there are a few
drivers that report errors at PCI bus. So, I don't see much problems using
it to report other hardware errors, like the ones associated with the
Ethernet hardware.

That's said, things like Ethernet frame errors are better handled via the
network drivers. I would report via EDAC only errors associated with the
Ethernet hardware that would cause the hardware to malfunction.

Btw, an UC error won't cause the system to halt, except if a UC memory
error happens and the EDAC core is loaded with an special modprobe
parameter (edac_mc_panic_on_ue = 1).

--
Thanks,
Mauro

2016-04-15 15:23:09

by Thor Thayer

[permalink] [raw]
Subject: Re: [PATCH] Add EDAC peripheral init functions & Ethernet EDAC.



On 04/15/2016 04:40 AM, Mauro Carvalho Chehab wrote:
> Em Thu, 14 Apr 2016 09:35:01 -0500
> Rob Herring <[email protected]> escreveu:
>
>> On Tue, Apr 12, 2016 at 05:12:55PM -0500, [email protected] wrote:
>>> This patch set adds the memory initialization functions for Altera's
>>> Arria10 peripherals, the first of which is the Ethernet EDAC. The
>>> first 3 patches add the memory initialization functionality. The
>>> last 3 patches add Ethernet EDAC support.
>>
>> The ethernet part seems a bit strange to me to put under EDAC as EDAC
>> is primarily memory controller ECC (and caches to some extent). Also you
>> would not halt the system in case of an UC, but rather just drop the
>> frame. This would need to be part of the ethernet driver in that case.
>>
>> Of course, given that ethernet frames already have a CRC, ECC of the
>> FIFO seems a bit redundant.
>
> Actually, EDAC was conceived to be a way to report hardware errors, and,
> although the main use case is for memory and CPU errors, there are a few
> drivers that report errors at PCI bus. So, I don't see much problems using
> it to report other hardware errors, like the ones associated with the
> Ethernet hardware.
>
> That's said, things like Ethernet frame errors are better handled via the
> network drivers. I would report via EDAC only errors associated with the
> Ethernet hardware that would cause the hardware to malfunction.
>
> Btw, an UC error won't cause the system to halt, except if a UC memory
> error happens and the EDAC core is loaded with an special modprobe
> parameter (edac_mc_panic_on_ue = 1).
>
Thank you for the clarification. Rob's comment was logical and made me
re-think this. He pointed out that I was causing a kernel panic in the
case of Uncorrectable errors which is not the desired response and will
need to change.

I'll update this patch to only count errors. I'll need to re-think how
the network driver can be alerted that there was an uncorrectable error
but that could be a later patch.

Great feedback. Thank you Mauro and Rob for reviewing and commenting!

2016-04-15 21:46:28

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH] Add EDAC peripheral init functions & Ethernet EDAC.

On Fri, Apr 15, 2016 at 10:27:54AM -0500, Thor Thayer wrote:
> I'll update this patch to only count errors.

... and also think about what that counting is going to bring. If it is
only going to be there to show how many network errors happened and we
can't do anything about it except stare at that number, then adding all
that code is probably waste of time an electrons...

I'm just sayin'.

--
Regards/Gruss,
Boris.

ECO tip #101: Trim your mails when you reply. Srsly.

2016-04-18 14:22:30

by Thor Thayer

[permalink] [raw]
Subject: Re: [PATCH] Add EDAC peripheral init functions & Ethernet EDAC.

Hi Boris,

On 04/15/2016 04:46 PM, Borislav Petkov wrote:
> On Fri, Apr 15, 2016 at 10:27:54AM -0500, Thor Thayer wrote:
>> I'll update this patch to only count errors.
>
> ... and also think about what that counting is going to bring. If it is
> only going to be there to show how many network errors happened and we
> can't do anything about it except stare at that number, then adding all
> that code is probably waste of time an electrons...
>
> I'm just sayin'.
>

Yes, valid point about the uncorrectable errors.

We're still getting the single bit correction which makes the entire
system more stable and the ability to see both single bit errors
corrected and the number of uncorrectable errors is useful from a system
point of view.

2016-04-18 20:02:34

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH] Add EDAC peripheral init functions & Ethernet EDAC.

On Mon, Apr 18, 2016 at 09:27:16AM -0500, Thor Thayer wrote:
> We're still getting the single bit correction

By that you mean, you get that by enabling ECC on the FIFO block?

> which makes the entire system more stable and the ability to see both
> single bit errors corrected and the number of uncorrectable errors is
> useful from a system point of view.

If so, that makes sense, yes.

Thanks.

--
Regards/Gruss,
Boris.

ECO tip #101: Trim your mails when you reply. Srsly.

2016-04-18 20:06:46

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH] Add EDAC peripheral init functions & Ethernet EDAC.

On Mon, Apr 18, 2016 at 10:02:27PM +0200, Borislav Petkov wrote:
> > the number of uncorrectable errors is useful from a system point of
> > view.

I forgot: so altr_edac_a10_ecc_irq() panics on uncorrectable errors. Do we want
to do that even for UEs coming from the network...?

Seems a bit overboard to me...

--
Regards/Gruss,
Boris.

ECO tip #101: Trim your mails when you reply. Srsly.

2016-04-18 20:11:08

by Thor Thayer

[permalink] [raw]
Subject: Re: [PATCH] Add EDAC peripheral init functions & Ethernet EDAC.


On 04/18/2016 03:02 PM, Borislav Petkov wrote:
> On Mon, Apr 18, 2016 at 09:27:16AM -0500, Thor Thayer wrote:
>> We're still getting the single bit correction
>
> By that you mean, you get that by enabling ECC on the FIFO block?
>
Yes, you are correct. I'd still get the single bit correction by
enabling ECC on the FIFO which is a win.

>> which makes the entire system more stable and the ability to see both
>> single bit errors corrected and the number of uncorrectable errors is
>> useful from a system point of view.
>
> If so, that makes sense, yes.
>
> Thanks.
>

2016-04-18 20:21:03

by Thor Thayer

[permalink] [raw]
Subject: Re: [PATCH] Add EDAC peripheral init functions & Ethernet EDAC.



On 04/18/2016 03:06 PM, Borislav Petkov wrote:
> On Mon, Apr 18, 2016 at 10:02:27PM +0200, Borislav Petkov wrote:
>>> the number of uncorrectable errors is useful from a system point of
>>> view.
>
> I forgot: so altr_edac_a10_ecc_irq() panics on uncorrectable errors. Do we want
> to do that even for UEs coming from the network...?
>
> Seems a bit overboard to me...
>

Yes, as currently submitted, it is overboard and I'll fix this in the
next patch submission. In the uncorrectable error case, I plan to just
count the error. I'll add a constant flag in the Ethernet module's
edac_device_prv_data to determine if the panic should be bypassed.