Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Thor Thayer and committed by
Borislav Petkov
c7b4be8d abd56b3c

+113
+78
drivers/edac/altera_edac.c
··· 550 550 551 551 const struct edac_device_prv_data ocramecc_data; 552 552 const struct edac_device_prv_data l2ecc_data; 553 + const struct edac_device_prv_data a10_ocramecc_data; 553 554 const struct edac_device_prv_data a10_l2ecc_data; 554 555 555 556 static irqreturn_t altr_edac_device_handler(int irq, void *dev_id) ··· 675 674 .llseek = generic_file_llseek, 676 675 }; 677 676 677 + static ssize_t altr_edac_a10_device_trig(struct file *file, 678 + const char __user *user_buf, 679 + size_t count, loff_t *ppos); 680 + 681 + static const struct file_operations altr_edac_a10_device_inject_fops = { 682 + .open = simple_open, 683 + .write = altr_edac_a10_device_trig, 684 + .llseek = generic_file_llseek, 685 + }; 686 + 678 687 static void altr_create_edacdev_dbgfs(struct edac_device_ctl_info *edac_dci, 679 688 const struct edac_device_prv_data *priv) 680 689 { ··· 712 701 #ifdef CONFIG_EDAC_ALTERA_OCRAM 713 702 { .compatible = "altr,socfpga-ocram-ecc", 714 703 .data = (void *)&ocramecc_data }, 704 + { .compatible = "altr,socfpga-a10-ocram-ecc", 705 + .data = (void *)&a10_ocramecc_data }, 715 706 #endif 716 707 {}, 717 708 }; ··· 902 889 .inject_fops = &altr_edac_device_inject_fops, 903 890 }; 904 891 892 + static irqreturn_t altr_edac_a10_ecc_irq(struct altr_edac_device_dev *dci, 893 + bool sberr); 894 + 895 + const struct edac_device_prv_data a10_ocramecc_data = { 896 + .setup = altr_check_ecc_deps, 897 + .ce_clear_mask = ALTR_A10_ECC_SERRPENA, 898 + .ue_clear_mask = ALTR_A10_ECC_DERRPENA, 899 + .irq_status_mask = A10_SYSMGR_ECC_INTSTAT_OCRAM, 900 + .dbgfs_name = "altr_ocram_trigger", 901 + .ecc_enable_mask = ALTR_A10_OCRAM_ECC_EN_CTL, 902 + .ecc_en_ofst = ALTR_A10_ECC_CTRL_OFST, 903 + .ce_set_mask = ALTR_A10_ECC_TSERRA, 904 + .ue_set_mask = ALTR_A10_ECC_TDERRA, 905 + .set_err_ofst = ALTR_A10_ECC_INTTEST_OFST, 906 + .ecc_irq_handler = altr_edac_a10_ecc_irq, 907 + .inject_fops = &altr_edac_a10_device_inject_fops, 908 + }; 909 + 905 910 #endif /* CONFIG_EDAC_ALTERA_OCRAM */ 906 911 907 912 /********************* L2 Cache EDAC Device Functions ********************/ ··· 1037 1006 * manager manages the IRQs and the children. 1038 1007 * Based on xgene_edac.c peripheral code. 1039 1008 */ 1009 + 1010 + static ssize_t altr_edac_a10_device_trig(struct file *file, 1011 + const char __user *user_buf, 1012 + size_t count, loff_t *ppos) 1013 + { 1014 + struct edac_device_ctl_info *edac_dci = file->private_data; 1015 + struct altr_edac_device_dev *drvdata = edac_dci->pvt_info; 1016 + const struct edac_device_prv_data *priv = drvdata->data; 1017 + void __iomem *set_addr = (drvdata->base + priv->set_err_ofst); 1018 + unsigned long flags; 1019 + u8 trig_type; 1020 + 1021 + if (!user_buf || get_user(trig_type, user_buf)) 1022 + return -EFAULT; 1023 + 1024 + local_irq_save(flags); 1025 + if (trig_type == ALTR_UE_TRIGGER_CHAR) 1026 + writel(priv->ue_set_mask, set_addr); 1027 + else 1028 + writel(priv->ce_set_mask, set_addr); 1029 + /* Ensure the interrupt test bits are set */ 1030 + wmb(); 1031 + local_irq_restore(flags); 1032 + 1033 + return count; 1034 + } 1035 + 1036 + static irqreturn_t altr_edac_a10_ecc_irq(struct altr_edac_device_dev *dci, 1037 + bool sberr) 1038 + { 1039 + void __iomem *base = dci->base; 1040 + 1041 + if (sberr) { 1042 + writel(ALTR_A10_ECC_SERRPENA, 1043 + base + ALTR_A10_ECC_INTSTAT_OFST); 1044 + edac_device_handle_ce(dci->edac_dev, 0, 0, dci->edac_dev_name); 1045 + } else { 1046 + writel(ALTR_A10_ECC_DERRPENA, 1047 + base + ALTR_A10_ECC_INTSTAT_OFST); 1048 + edac_device_handle_ue(dci->edac_dev, 0, 0, dci->edac_dev_name); 1049 + panic("\nEDAC:ECC_DEVICE[Uncorrectable errors]\n"); 1050 + } 1051 + return IRQ_HANDLED; 1052 + } 1040 1053 1041 1054 static irqreturn_t altr_edac_a10_irq_handler(int irq, void *dev_id) 1042 1055 { ··· 1245 1170 if (!of_device_is_available(child)) 1246 1171 continue; 1247 1172 if (of_device_is_compatible(child, "altr,socfpga-a10-l2-ecc")) 1173 + altr_edac_a10_device_add(edac, child); 1174 + else if (of_device_is_compatible(child, 1175 + "altr,socfpga-a10-ocram-ecc")) 1248 1176 altr_edac_a10_device_add(edac, child); 1249 1177 } 1250 1178
+35
drivers/edac/altera_edac.h
··· 220 220 #define ALTR_L2_ECC_INJD BIT(2) 221 221 222 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 254 #define A10_SYSMGR_ECC_INTSTAT_SERR_OFST 0x9C 224 255 #define A10_SYSMGR_ECC_INTSTAT_DERR_OFST 0xA0 225 256 #define A10_SYSMGR_ECC_INTSTAT_L2 BIT(0) 257 + #define A10_SYSMGR_ECC_INTSTAT_OCRAM BIT(1) 226 258 227 259 #define A10_SYSGMR_MPU_CLEAR_L2_ECC_OFST 0xA8 228 260 #define A10_SYSGMR_MPU_CLEAR_L2_ECC_SB BIT(15) ··· 276 244 #define ALTR_A10_L2_ECC_INJ_OFST ALTR_A10_L2_ECC_CTL_OFST 277 245 #define ALTR_A10_L2_ECC_CE_INJ_MASK 0x00000101 278 246 #define ALTR_A10_L2_ECC_UE_INJ_MASK 0x00010101 247 + 248 + /* Arria 10 OCRAM ECC Management Group Defines */ 249 + #define ALTR_A10_OCRAM_ECC_EN_CTL (BIT(1) | BIT(0)) 279 250 280 251 struct altr_edac_device_dev; 281 252