aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThor Thayer <tthayer@opensource.altera.com>2016-03-21 12:01:44 -0400
committerBorislav Petkov <bp@suse.de>2016-03-29 04:34:06 -0400
commit588cb03ea208b303e6dee7e916f329043fd0fc26 (patch)
treeacc1e591b446c8bee8016c33f6b7fbf8bf277b8c
parent8b39ab7290d571b91867b15c02a59edf0a5b00bb (diff)
EDAC, altera: Add Arria10 L2 Cache ECC handling
Add a private data structure for Arria10 L2 cache ECC and the probe function for it. The Arria10 ECC device IRQs are in a shared register so the ECC Manager parent/child relationship requires a different probe function. 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/1458576106-24505-8-git-send-email-tthayer@opensource.altera.com Signed-off-by: Borislav Petkov <bp@suse.de>
-rw-r--r--drivers/edac/altera_edac.c231
-rw-r--r--drivers/edac/altera_edac.h42
2 files changed, 273 insertions, 0 deletions
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
index 502bf1fcf9e5..0afdc582766e 100644
--- a/drivers/edac/altera_edac.c
+++ b/drivers/edac/altera_edac.c
@@ -24,6 +24,7 @@
24#include <linux/interrupt.h> 24#include <linux/interrupt.h>
25#include <linux/kernel.h> 25#include <linux/kernel.h>
26#include <linux/mfd/syscon.h> 26#include <linux/mfd/syscon.h>
27#include <linux/of_address.h>
27#include <linux/of_platform.h> 28#include <linux/of_platform.h>
28#include <linux/platform_device.h> 29#include <linux/platform_device.h>
29#include <linux/regmap.h> 30#include <linux/regmap.h>
@@ -549,6 +550,7 @@ module_platform_driver(altr_edac_driver);
549 550
550const struct edac_device_prv_data ocramecc_data; 551const struct edac_device_prv_data ocramecc_data;
551const struct edac_device_prv_data l2ecc_data; 552const struct edac_device_prv_data l2ecc_data;
553const struct edac_device_prv_data a10_l2ecc_data;
552 554
553static irqreturn_t altr_edac_device_handler(int irq, void *dev_id) 555static irqreturn_t altr_edac_device_handler(int irq, void *dev_id)
554{ 556{
@@ -673,6 +675,8 @@ static void altr_create_edacdev_dbgfs(struct edac_device_ctl_info *edac_dci,
673static const struct of_device_id altr_edac_device_of_match[] = { 675static const struct of_device_id altr_edac_device_of_match[] = {
674#ifdef CONFIG_EDAC_ALTERA_L2C 676#ifdef CONFIG_EDAC_ALTERA_L2C
675 { .compatible = "altr,socfpga-l2-ecc", .data = (void *)&l2ecc_data }, 677 { .compatible = "altr,socfpga-l2-ecc", .data = (void *)&l2ecc_data },
678 { .compatible = "altr,socfpga-a10-l2-ecc",
679 .data = (void *)&a10_l2ecc_data },
676#endif 680#endif
677#ifdef CONFIG_EDAC_ALTERA_OCRAM 681#ifdef CONFIG_EDAC_ALTERA_OCRAM
678 { .compatible = "altr,socfpga-ocram-ecc", 682 { .compatible = "altr,socfpga-ocram-ecc",
@@ -941,6 +945,24 @@ static int altr_l2_check_deps(struct altr_edac_device_dev *device)
941 return -ENODEV; 945 return -ENODEV;
942} 946}
943 947
948static irqreturn_t altr_edac_a10_l2_irq(struct altr_edac_device_dev *dci,
949 bool sberr)
950{
951 if (sberr) {
952 regmap_write(dci->edac->ecc_mgr_map,
953 A10_SYSGMR_MPU_CLEAR_L2_ECC_OFST,
954 A10_SYSGMR_MPU_CLEAR_L2_ECC_SB);
955 edac_device_handle_ce(dci->edac_dev, 0, 0, dci->edac_dev_name);
956 } else {
957 regmap_write(dci->edac->ecc_mgr_map,
958 A10_SYSGMR_MPU_CLEAR_L2_ECC_OFST,
959 A10_SYSGMR_MPU_CLEAR_L2_ECC_MB);
960 edac_device_handle_ue(dci->edac_dev, 0, 0, dci->edac_dev_name);
961 panic("\nEDAC:ECC_DEVICE[Uncorrectable errors]\n");
962 }
963 return IRQ_HANDLED;
964}
965
944const struct edac_device_prv_data l2ecc_data = { 966const struct edac_device_prv_data l2ecc_data = {
945 .setup = altr_l2_check_deps, 967 .setup = altr_l2_check_deps,
946 .ce_clear_mask = 0, 968 .ce_clear_mask = 0,
@@ -955,8 +977,217 @@ const struct edac_device_prv_data l2ecc_data = {
955 .trig_alloc_sz = ALTR_TRIG_L2C_BYTE_SIZE, 977 .trig_alloc_sz = ALTR_TRIG_L2C_BYTE_SIZE,
956}; 978};
957 979
980const struct edac_device_prv_data a10_l2ecc_data = {
981 .setup = altr_l2_check_deps,
982 .ce_clear_mask = ALTR_A10_L2_ECC_SERR_CLR,
983 .ue_clear_mask = ALTR_A10_L2_ECC_MERR_CLR,
984 .irq_status_mask = A10_SYSMGR_ECC_INTSTAT_L2,
985 .dbgfs_name = "altr_l2_trigger",
986 .alloc_mem = l2_alloc_mem,
987 .free_mem = l2_free_mem,
988 .ecc_enable_mask = ALTR_A10_L2_ECC_EN_CTL,
989 .ce_set_mask = ALTR_A10_L2_ECC_CE_INJ_MASK,
990 .ue_set_mask = ALTR_A10_L2_ECC_UE_INJ_MASK,
991 .set_err_ofst = ALTR_A10_L2_ECC_INJ_OFST,
992 .ecc_irq_handler = altr_edac_a10_l2_irq,
993 .trig_alloc_sz = ALTR_TRIG_L2C_BYTE_SIZE,
994};
995
958#endif /* CONFIG_EDAC_ALTERA_L2C */ 996#endif /* CONFIG_EDAC_ALTERA_L2C */
959 997
998/********************* Arria10 EDAC Device Functions *************************/
999
1000/*
1001 * The Arria10 EDAC Device Functions differ from the Cyclone5/Arria5
1002 * because 2 IRQs are shared among the all ECC peripherals. The ECC
1003 * manager manages the IRQs and the children.
1004 * Based on xgene_edac.c peripheral code.
1005 */
1006
1007static irqreturn_t altr_edac_a10_irq_handler(int irq, void *dev_id)
1008{
1009 irqreturn_t rc = IRQ_NONE;
1010 struct altr_arria10_edac *edac = dev_id;
1011 struct altr_edac_device_dev *dci;
1012 int irq_status;
1013 bool sberr = (irq == edac->sb_irq) ? 1 : 0;
1014 int sm_offset = sberr ? A10_SYSMGR_ECC_INTSTAT_SERR_OFST :
1015 A10_SYSMGR_ECC_INTSTAT_DERR_OFST;
1016
1017 regmap_read(edac->ecc_mgr_map, sm_offset, &irq_status);
1018
1019 if ((irq != edac->sb_irq) && (irq != edac->db_irq)) {
1020 WARN_ON(1);
1021 } else {
1022 list_for_each_entry(dci, &edac->a10_ecc_devices, next) {
1023 if (irq_status & dci->data->irq_status_mask)
1024 rc = dci->data->ecc_irq_handler(dci, sberr);
1025 }
1026 }
1027
1028 return rc;
1029}
1030
1031static int altr_edac_a10_device_add(struct altr_arria10_edac *edac,
1032 struct device_node *np)
1033{
1034 struct edac_device_ctl_info *dci;
1035 struct altr_edac_device_dev *altdev;
1036 char *ecc_name = (char *)np->name;
1037 struct resource res;
1038 int edac_idx;
1039 int rc = 0;
1040 const struct edac_device_prv_data *prv;
1041 /* Get matching node and check for valid result */
1042 const struct of_device_id *pdev_id =
1043 of_match_node(altr_edac_device_of_match, np);
1044 if (IS_ERR_OR_NULL(pdev_id))
1045 return -ENODEV;
1046
1047 /* Get driver specific data for this EDAC device */
1048 prv = pdev_id->data;
1049 if (IS_ERR_OR_NULL(prv))
1050 return -ENODEV;
1051
1052 if (!devres_open_group(edac->dev, altr_edac_a10_device_add, GFP_KERNEL))
1053 return -ENOMEM;
1054
1055 rc = of_address_to_resource(np, 0, &res);
1056 if (rc < 0) {
1057 edac_printk(KERN_ERR, EDAC_DEVICE,
1058 "%s: no resource address\n", ecc_name);
1059 goto err_release_group;
1060 }
1061
1062 edac_idx = edac_device_alloc_index();
1063 dci = edac_device_alloc_ctl_info(sizeof(*altdev), ecc_name,
1064 1, ecc_name, 1, 0, NULL, 0,
1065 edac_idx);
1066
1067 if (!dci) {
1068 edac_printk(KERN_ERR, EDAC_DEVICE,
1069 "%s: Unable to allocate EDAC device\n", ecc_name);
1070 rc = -ENOMEM;
1071 goto err_release_group;
1072 }
1073
1074 altdev = dci->pvt_info;
1075 dci->dev = edac->dev;
1076 altdev->edac_dev_name = ecc_name;
1077 altdev->edac_idx = edac_idx;
1078 altdev->edac = edac;
1079 altdev->edac_dev = dci;
1080 altdev->data = prv;
1081 altdev->ddev = *edac->dev;
1082 dci->dev = &altdev->ddev;
1083 dci->ctl_name = "Altera ECC Manager";
1084 dci->mod_name = ecc_name;
1085 dci->dev_name = ecc_name;
1086
1087 altdev->base = devm_ioremap_resource(edac->dev, &res);
1088 if (IS_ERR(altdev->base)) {
1089 rc = PTR_ERR(altdev->base);
1090 goto err_release_group1;
1091 }
1092
1093 /* Check specific dependencies for the module */
1094 if (altdev->data->setup) {
1095 rc = altdev->data->setup(altdev);
1096 if (rc)
1097 goto err_release_group1;
1098 }
1099
1100 rc = edac_device_add_device(dci);
1101 if (rc) {
1102 dev_err(edac->dev, "edac_device_add_device failed\n");
1103 rc = -ENOMEM;
1104 goto err_release_group1;
1105 }
1106
1107 altr_create_edacdev_dbgfs(dci, prv);
1108
1109 list_add(&altdev->next, &edac->a10_ecc_devices);
1110
1111 devres_remove_group(edac->dev, altr_edac_a10_device_add);
1112
1113 return 0;
1114
1115err_release_group1:
1116 edac_device_free_ctl_info(dci);
1117err_release_group:
1118 edac_printk(KERN_ALERT, EDAC_DEVICE, "%s: %d\n", __func__, __LINE__);
1119 devres_release_group(edac->dev, NULL);
1120 edac_printk(KERN_ERR, EDAC_DEVICE,
1121 "%s:Error setting up EDAC device: %d\n", ecc_name, rc);
1122
1123 return rc;
1124}
1125
1126static int altr_edac_a10_probe(struct platform_device *pdev)
1127{
1128 struct altr_arria10_edac *edac;
1129 struct device_node *child;
1130 int rc;
1131
1132 edac = devm_kzalloc(&pdev->dev, sizeof(*edac), GFP_KERNEL);
1133 if (!edac)
1134 return -ENOMEM;
1135
1136 edac->dev = &pdev->dev;
1137 platform_set_drvdata(pdev, edac);
1138 INIT_LIST_HEAD(&edac->a10_ecc_devices);
1139
1140 edac->ecc_mgr_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
1141 "altr,sysmgr-syscon");
1142 if (IS_ERR(edac->ecc_mgr_map)) {
1143 edac_printk(KERN_ERR, EDAC_DEVICE,
1144 "Unable to get syscon altr,sysmgr-syscon\n");
1145 return PTR_ERR(edac->ecc_mgr_map);
1146 }
1147
1148 edac->sb_irq = platform_get_irq(pdev, 0);
1149 rc = devm_request_irq(&pdev->dev, edac->sb_irq,
1150 altr_edac_a10_irq_handler,
1151 IRQF_SHARED, dev_name(&pdev->dev), edac);
1152 if (rc) {
1153 edac_printk(KERN_ERR, EDAC_DEVICE, "No SBERR IRQ resource\n");
1154 return rc;
1155 }
1156
1157 edac->db_irq = platform_get_irq(pdev, 1);
1158 rc = devm_request_irq(&pdev->dev, edac->db_irq,
1159 altr_edac_a10_irq_handler,
1160 IRQF_SHARED, dev_name(&pdev->dev), edac);
1161 if (rc) {
1162 edac_printk(KERN_ERR, EDAC_DEVICE, "No DBERR IRQ resource\n");
1163 return rc;
1164 }
1165
1166 for_each_child_of_node(pdev->dev.of_node, child) {
1167 if (!of_device_is_available(child))
1168 continue;
1169 if (of_device_is_compatible(child, "altr,socfpga-a10-l2-ecc"))
1170 altr_edac_a10_device_add(edac, child);
1171 }
1172
1173 return 0;
1174}
1175
1176static const struct of_device_id altr_edac_a10_of_match[] = {
1177 { .compatible = "altr,socfpga-a10-ecc-manager" },
1178 {},
1179};
1180MODULE_DEVICE_TABLE(of, altr_edac_a10_of_match);
1181
1182static struct platform_driver altr_edac_a10_driver = {
1183 .probe = altr_edac_a10_probe,
1184 .driver = {
1185 .name = "socfpga_a10_ecc_manager",
1186 .of_match_table = altr_edac_a10_of_match,
1187 },
1188};
1189module_platform_driver(altr_edac_a10_driver);
1190
960MODULE_LICENSE("GPL v2"); 1191MODULE_LICENSE("GPL v2");
961MODULE_AUTHOR("Thor Thayer"); 1192MODULE_AUTHOR("Thor Thayer");
962MODULE_DESCRIPTION("EDAC Driver for Altera Memories"); 1193MODULE_DESCRIPTION("EDAC Driver for Altera Memories");
diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h
index d7ef94c13b98..b0a17d03c715 100644
--- a/drivers/edac/altera_edac.h
+++ b/drivers/edac/altera_edac.h
@@ -219,12 +219,39 @@ struct altr_sdram_mc_data {
219#define ALTR_L2_ECC_INJS BIT(1) 219#define ALTR_L2_ECC_INJS BIT(1)
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 */
223#define A10_SYSMGR_ECC_INTSTAT_SERR_OFST 0x9C
224#define A10_SYSMGR_ECC_INTSTAT_DERR_OFST 0xA0
225#define A10_SYSMGR_ECC_INTSTAT_L2 BIT(0)
226
227#define A10_SYSGMR_MPU_CLEAR_L2_ECC_OFST 0xA8
228#define A10_SYSGMR_MPU_CLEAR_L2_ECC_SB BIT(15)
229#define A10_SYSGMR_MPU_CLEAR_L2_ECC_MB BIT(31)
230
231/* Arria 10 L2 ECC Management Group Defines */
232#define ALTR_A10_L2_ECC_CTL_OFST 0x0
233#define ALTR_A10_L2_ECC_EN_CTL BIT(0)
234
235#define ALTR_A10_L2_ECC_STATUS 0xFFD060A4
236#define ALTR_A10_L2_ECC_STAT_OFST 0xA4
237#define ALTR_A10_L2_ECC_SERR_PEND BIT(0)
238#define ALTR_A10_L2_ECC_MERR_PEND BIT(0)
239
240#define ALTR_A10_L2_ECC_CLR_OFST 0x4
241#define ALTR_A10_L2_ECC_SERR_CLR BIT(15)
242#define ALTR_A10_L2_ECC_MERR_CLR BIT(31)
243
244#define ALTR_A10_L2_ECC_INJ_OFST ALTR_A10_L2_ECC_CTL_OFST
245#define ALTR_A10_L2_ECC_CE_INJ_MASK 0x00000101
246#define ALTR_A10_L2_ECC_UE_INJ_MASK 0x00010101
247
222struct altr_edac_device_dev; 248struct altr_edac_device_dev;
223 249
224struct edac_device_prv_data { 250struct edac_device_prv_data {
225 int (*setup)(struct altr_edac_device_dev *device); 251 int (*setup)(struct altr_edac_device_dev *device);
226 int ce_clear_mask; 252 int ce_clear_mask;
227 int ue_clear_mask; 253 int ue_clear_mask;
254 int irq_status_mask;
228 char dbgfs_name[20]; 255 char dbgfs_name[20];
229 void * (*alloc_mem)(size_t size, void **other); 256 void * (*alloc_mem)(size_t size, void **other);
230 void (*free_mem)(void *p, size_t size, void *other); 257 void (*free_mem)(void *p, size_t size, void *other);
@@ -232,16 +259,31 @@ struct edac_device_prv_data {
232 int ce_set_mask; 259 int ce_set_mask;
233 int ue_set_mask; 260 int ue_set_mask;
234 int set_err_ofst; 261 int set_err_ofst;
262 irqreturn_t (*ecc_irq_handler)(struct altr_edac_device_dev *dci,
263 bool sb);
235 int trig_alloc_sz; 264 int trig_alloc_sz;
236}; 265};
237 266
238struct altr_edac_device_dev { 267struct altr_edac_device_dev {
268 struct list_head next;
239 void __iomem *base; 269 void __iomem *base;
240 int sb_irq; 270 int sb_irq;
241 int db_irq; 271 int db_irq;
242 const struct edac_device_prv_data *data; 272 const struct edac_device_prv_data *data;
243 struct dentry *debugfs_dir; 273 struct dentry *debugfs_dir;
244 char *edac_dev_name; 274 char *edac_dev_name;
275 struct altr_arria10_edac *edac;
276 struct edac_device_ctl_info *edac_dev;
277 struct device ddev;
278 int edac_idx;
279};
280
281struct altr_arria10_edac {
282 struct device *dev;
283 struct regmap *ecc_mgr_map;
284 int sb_irq;
285 int db_irq;
286 struct list_head a10_ecc_devices;
245}; 287};
246 288
247#endif /* #ifndef _ALTERA_EDAC_H */ 289#endif /* #ifndef _ALTERA_EDAC_H */