aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThor Thayer <tthayer@opensource.altera.com>2016-04-06 21:22:54 -0400
committerBorislav Petkov <bp@suse.de>2016-04-07 06:42:56 -0400
commitc7b4be8db8bc33ec60d21940b3d78b203cdffaac (patch)
tree35ededd3a77a324501391887e5a3d9b456153038
parentabd56b3c8483ca73413ade0e7c7a0d13b9870016 (diff)
EDAC, altera: Add Arria10 OCRAM ECC support
Add Arria10 On-Chip RAM ECC handling. Signed-off-by: Thor Thayer <tthayer@opensource.altera.com> Cc: devicetree@vger.kernel.org Cc: dinguyen@opensource.altera.com Cc: linux-arm-kernel@lists.infradead.org Cc: linux@arm.linux.org.uk Cc: linux-edac <linux-edac@vger.kernel.org> Link: http://lkml.kernel.org/r/1459992174-8015-1-git-send-email-tthayer@opensource.altera.com Signed-off-by: Borislav Petkov <bp@suse.de>
-rw-r--r--drivers/edac/altera_edac.c78
-rw-r--r--drivers/edac/altera_edac.h35
2 files changed, 113 insertions, 0 deletions
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
index f7ffc77998a4..11775dc0b139 100644
--- a/drivers/edac/altera_edac.c
+++ b/drivers/edac/altera_edac.c
@@ -550,6 +550,7 @@ module_platform_driver(altr_edac_driver);
550 550
551const struct edac_device_prv_data ocramecc_data; 551const struct edac_device_prv_data ocramecc_data;
552const struct edac_device_prv_data l2ecc_data; 552const struct edac_device_prv_data l2ecc_data;
553const struct edac_device_prv_data a10_ocramecc_data;
553const struct edac_device_prv_data a10_l2ecc_data; 554const struct edac_device_prv_data a10_l2ecc_data;
554 555
555static irqreturn_t altr_edac_device_handler(int irq, void *dev_id) 556static irqreturn_t altr_edac_device_handler(int irq, void *dev_id)
@@ -674,6 +675,16 @@ static const struct file_operations altr_edac_device_inject_fops = {
674 .llseek = generic_file_llseek, 675 .llseek = generic_file_llseek,
675}; 676};
676 677
678static ssize_t altr_edac_a10_device_trig(struct file *file,
679 const char __user *user_buf,
680 size_t count, loff_t *ppos);
681
682static const struct file_operations altr_edac_a10_device_inject_fops = {
683 .open = simple_open,
684 .write = altr_edac_a10_device_trig,
685 .llseek = generic_file_llseek,
686};
687
677static void altr_create_edacdev_dbgfs(struct edac_device_ctl_info *edac_dci, 688static void altr_create_edacdev_dbgfs(struct edac_device_ctl_info *edac_dci,
678 const struct edac_device_prv_data *priv) 689 const struct edac_device_prv_data *priv)
679{ 690{
@@ -701,6 +712,8 @@ static const struct of_device_id altr_edac_device_of_match[] = {
701#ifdef CONFIG_EDAC_ALTERA_OCRAM 712#ifdef CONFIG_EDAC_ALTERA_OCRAM
702 { .compatible = "altr,socfpga-ocram-ecc", 713 { .compatible = "altr,socfpga-ocram-ecc",
703 .data = (void *)&ocramecc_data }, 714 .data = (void *)&ocramecc_data },
715 { .compatible = "altr,socfpga-a10-ocram-ecc",
716 .data = (void *)&a10_ocramecc_data },
704#endif 717#endif
705 {}, 718 {},
706}; 719};
@@ -889,6 +902,24 @@ const struct edac_device_prv_data ocramecc_data = {
889 .inject_fops = &altr_edac_device_inject_fops, 902 .inject_fops = &altr_edac_device_inject_fops,
890}; 903};
891 904
905static irqreturn_t altr_edac_a10_ecc_irq(struct altr_edac_device_dev *dci,
906 bool sberr);
907
908const struct edac_device_prv_data a10_ocramecc_data = {
909 .setup = altr_check_ecc_deps,
910 .ce_clear_mask = ALTR_A10_ECC_SERRPENA,
911 .ue_clear_mask = ALTR_A10_ECC_DERRPENA,
912 .irq_status_mask = A10_SYSMGR_ECC_INTSTAT_OCRAM,
913 .dbgfs_name = "altr_ocram_trigger",
914 .ecc_enable_mask = ALTR_A10_OCRAM_ECC_EN_CTL,
915 .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST,
916 .ce_set_mask = ALTR_A10_ECC_TSERRA,
917 .ue_set_mask = ALTR_A10_ECC_TDERRA,
918 .set_err_ofst = ALTR_A10_ECC_INTTEST_OFST,
919 .ecc_irq_handler = altr_edac_a10_ecc_irq,
920 .inject_fops = &altr_edac_a10_device_inject_fops,
921};
922
892#endif /* CONFIG_EDAC_ALTERA_OCRAM */ 923#endif /* CONFIG_EDAC_ALTERA_OCRAM */
893 924
894/********************* L2 Cache EDAC Device Functions ********************/ 925/********************* L2 Cache EDAC Device Functions ********************/
@@ -1007,6 +1038,50 @@ const struct edac_device_prv_data a10_l2ecc_data = {
1007 * Based on xgene_edac.c peripheral code. 1038 * Based on xgene_edac.c peripheral code.
1008 */ 1039 */
1009 1040
1041static ssize_t altr_edac_a10_device_trig(struct file *file,
1042 const char __user *user_buf,
1043 size_t count, loff_t *ppos)
1044{
1045 struct edac_device_ctl_info *edac_dci = file->private_data;
1046 struct altr_edac_device_dev *drvdata = edac_dci->pvt_info;
1047 const struct edac_device_prv_data *priv = drvdata->data;
1048 void __iomem *set_addr = (drvdata->base + priv->set_err_ofst);
1049 unsigned long flags;
1050 u8 trig_type;
1051
1052 if (!user_buf || get_user(trig_type, user_buf))
1053 return -EFAULT;
1054
1055 local_irq_save(flags);
1056 if (trig_type == ALTR_UE_TRIGGER_CHAR)
1057 writel(priv->ue_set_mask, set_addr);
1058 else
1059 writel(priv->ce_set_mask, set_addr);
1060 /* Ensure the interrupt test bits are set */
1061 wmb();
1062 local_irq_restore(flags);
1063
1064 return count;
1065}
1066
1067static irqreturn_t altr_edac_a10_ecc_irq(struct altr_edac_device_dev *dci,
1068 bool sberr)
1069{
1070 void __iomem *base = dci->base;
1071
1072 if (sberr) {
1073 writel(ALTR_A10_ECC_SERRPENA,
1074 base + ALTR_A10_ECC_INTSTAT_OFST);
1075 edac_device_handle_ce(dci->edac_dev, 0, 0, dci->edac_dev_name);
1076 } else {
1077 writel(ALTR_A10_ECC_DERRPENA,
1078 base + ALTR_A10_ECC_INTSTAT_OFST);
1079 edac_device_handle_ue(dci->edac_dev, 0, 0, dci->edac_dev_name);
1080 panic("\nEDAC:ECC_DEVICE[Uncorrectable errors]\n");
1081 }
1082 return IRQ_HANDLED;
1083}
1084
1010static irqreturn_t altr_edac_a10_irq_handler(int irq, void *dev_id) 1085static irqreturn_t altr_edac_a10_irq_handler(int irq, void *dev_id)
1011{ 1086{
1012 irqreturn_t rc = IRQ_NONE; 1087 irqreturn_t rc = IRQ_NONE;
@@ -1171,6 +1246,9 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
1171 continue; 1246 continue;
1172 if (of_device_is_compatible(child, "altr,socfpga-a10-l2-ecc")) 1247 if (of_device_is_compatible(child, "altr,socfpga-a10-l2-ecc"))
1173 altr_edac_a10_device_add(edac, child); 1248 altr_edac_a10_device_add(edac, child);
1249 else if (of_device_is_compatible(child,
1250 "altr,socfpga-a10-ocram-ecc"))
1251 altr_edac_a10_device_add(edac, child);
1174 } 1252 }
1175 1253
1176 return 0; 1254 return 0;
diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h
index cb6b2b9079e8..42090f36ba6e 100644
--- a/drivers/edac/altera_edac.h
+++ b/drivers/edac/altera_edac.h
@@ -220,9 +220,41 @@ struct altr_sdram_mc_data {
220#define ALTR_L2_ECC_INJD BIT(2) 220#define ALTR_L2_ECC_INJD BIT(2)
221 221
222/* Arria10 General ECC Block Module Defines */ 222/* Arria10 General ECC Block Module Defines */
223#define ALTR_A10_ECC_CTRL_OFST 0x08
224#define ALTR_A10_ECC_EN BIT(0)
225#define ALTR_A10_ECC_INITA BIT(16)
226#define ALTR_A10_ECC_INITB BIT(24)
227
228#define ALTR_A10_ECC_INITSTAT_OFST 0x0C
229#define ALTR_A10_ECC_INITCOMPLETEA BIT(0)
230#define ALTR_A10_ECC_INITCOMPLETEB BIT(8)
231
232#define ALTR_A10_ECC_ERRINTEN_OFST 0x10
233#define ALTR_A10_ECC_SERRINTEN BIT(0)
234
235#define ALTR_A10_ECC_INTSTAT_OFST 0x20
236#define ALTR_A10_ECC_SERRPENA BIT(0)
237#define ALTR_A10_ECC_DERRPENA BIT(8)
238#define ALTR_A10_ECC_ERRPENA_MASK (ALTR_A10_ECC_SERRPENA | \
239 ALTR_A10_ECC_DERRPENA)
240#define ALTR_A10_ECC_SERRPENB BIT(16)
241#define ALTR_A10_ECC_DERRPENB BIT(24)
242#define ALTR_A10_ECC_ERRPENB_MASK (ALTR_A10_ECC_SERRPENB | \
243 ALTR_A10_ECC_DERRPENB)
244
245#define ALTR_A10_ECC_INTTEST_OFST 0x24
246#define ALTR_A10_ECC_TSERRA BIT(0)
247#define ALTR_A10_ECC_TDERRA BIT(8)
248
249/* ECC Manager Defines */
250#define A10_SYSMGR_ECC_INTMASK_SET_OFST 0x94
251#define A10_SYSMGR_ECC_INTMASK_CLR_OFST 0x98
252#define A10_SYSMGR_ECC_INTMASK_OCRAM BIT(1)
253
223#define A10_SYSMGR_ECC_INTSTAT_SERR_OFST 0x9C 254#define A10_SYSMGR_ECC_INTSTAT_SERR_OFST 0x9C
224#define A10_SYSMGR_ECC_INTSTAT_DERR_OFST 0xA0 255#define A10_SYSMGR_ECC_INTSTAT_DERR_OFST 0xA0
225#define A10_SYSMGR_ECC_INTSTAT_L2 BIT(0) 256#define A10_SYSMGR_ECC_INTSTAT_L2 BIT(0)
257#define A10_SYSMGR_ECC_INTSTAT_OCRAM BIT(1)
226 258
227#define A10_SYSGMR_MPU_CLEAR_L2_ECC_OFST 0xA8 259#define A10_SYSGMR_MPU_CLEAR_L2_ECC_OFST 0xA8
228#define A10_SYSGMR_MPU_CLEAR_L2_ECC_SB BIT(15) 260#define A10_SYSGMR_MPU_CLEAR_L2_ECC_SB BIT(15)
@@ -245,6 +277,9 @@ struct altr_sdram_mc_data {
245#define ALTR_A10_L2_ECC_CE_INJ_MASK 0x00000101 277#define ALTR_A10_L2_ECC_CE_INJ_MASK 0x00000101
246#define ALTR_A10_L2_ECC_UE_INJ_MASK 0x00010101 278#define ALTR_A10_L2_ECC_UE_INJ_MASK 0x00010101
247 279
280/* Arria 10 OCRAM ECC Management Group Defines */
281#define ALTR_A10_OCRAM_ECC_EN_CTL (BIT(1) | BIT(0))
282
248struct altr_edac_device_dev; 283struct altr_edac_device_dev;
249 284
250struct edac_device_prv_data { 285struct edac_device_prv_data {