aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/edac/altera_edac.c167
-rw-r--r--drivers/edac/altera_edac.h5
2 files changed, 130 insertions, 42 deletions
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
index 5b4d223d6d68..c254f90b2e70 100644
--- a/drivers/edac/altera_edac.c
+++ b/drivers/edac/altera_edac.c
@@ -22,9 +22,11 @@
22#include <linux/edac.h> 22#include <linux/edac.h>
23#include <linux/genalloc.h> 23#include <linux/genalloc.h>
24#include <linux/interrupt.h> 24#include <linux/interrupt.h>
25#include <linux/irqchip/chained_irq.h>
25#include <linux/kernel.h> 26#include <linux/kernel.h>
26#include <linux/mfd/syscon.h> 27#include <linux/mfd/syscon.h>
27#include <linux/of_address.h> 28#include <linux/of_address.h>
29#include <linux/of_irq.h>
28#include <linux/of_platform.h> 30#include <linux/of_platform.h>
29#include <linux/platform_device.h> 31#include <linux/platform_device.h>
30#include <linux/regmap.h> 32#include <linux/regmap.h>
@@ -882,22 +884,29 @@ static void ocram_free_mem(void *p, size_t size, void *other)
882 gen_pool_free((struct gen_pool *)other, (u32)p, size); 884 gen_pool_free((struct gen_pool *)other, (u32)p, size);
883} 885}
884 886
885static irqreturn_t altr_edac_a10_ecc_irq(struct altr_edac_device_dev *dci, 887static irqreturn_t altr_edac_a10_ecc_irq(int irq, void *dev_id)
886 bool sberr)
887{ 888{
889 struct altr_edac_device_dev *dci = dev_id;
888 void __iomem *base = dci->base; 890 void __iomem *base = dci->base;
889 891
890 if (sberr) { 892 if (irq == dci->sb_irq) {
891 writel(ALTR_A10_ECC_SERRPENA, 893 writel(ALTR_A10_ECC_SERRPENA,
892 base + ALTR_A10_ECC_INTSTAT_OFST); 894 base + ALTR_A10_ECC_INTSTAT_OFST);
893 edac_device_handle_ce(dci->edac_dev, 0, 0, dci->edac_dev_name); 895 edac_device_handle_ce(dci->edac_dev, 0, 0, dci->edac_dev_name);
894 } else { 896
897 return IRQ_HANDLED;
898 } else if (irq == dci->db_irq) {
895 writel(ALTR_A10_ECC_DERRPENA, 899 writel(ALTR_A10_ECC_DERRPENA,
896 base + ALTR_A10_ECC_INTSTAT_OFST); 900 base + ALTR_A10_ECC_INTSTAT_OFST);
897 edac_device_handle_ue(dci->edac_dev, 0, 0, dci->edac_dev_name); 901 edac_device_handle_ue(dci->edac_dev, 0, 0, dci->edac_dev_name);
898 panic("\nEDAC:ECC_DEVICE[Uncorrectable errors]\n"); 902 panic("\nEDAC:ECC_DEVICE[Uncorrectable errors]\n");
903
904 return IRQ_HANDLED;
899 } 905 }
900 return IRQ_HANDLED; 906
907 WARN_ON(1);
908
909 return IRQ_NONE;
901} 910}
902 911
903const struct edac_device_prv_data ocramecc_data = { 912const struct edac_device_prv_data ocramecc_data = {
@@ -988,22 +997,30 @@ static int altr_l2_check_deps(struct altr_edac_device_dev *device)
988 return -ENODEV; 997 return -ENODEV;
989} 998}
990 999
991static irqreturn_t altr_edac_a10_l2_irq(struct altr_edac_device_dev *dci, 1000static irqreturn_t altr_edac_a10_l2_irq(int irq, void *dev_id)
992 bool sberr)
993{ 1001{
994 if (sberr) { 1002 struct altr_edac_device_dev *dci = dev_id;
1003
1004 if (irq == dci->sb_irq) {
995 regmap_write(dci->edac->ecc_mgr_map, 1005 regmap_write(dci->edac->ecc_mgr_map,
996 A10_SYSGMR_MPU_CLEAR_L2_ECC_OFST, 1006 A10_SYSGMR_MPU_CLEAR_L2_ECC_OFST,
997 A10_SYSGMR_MPU_CLEAR_L2_ECC_SB); 1007 A10_SYSGMR_MPU_CLEAR_L2_ECC_SB);
998 edac_device_handle_ce(dci->edac_dev, 0, 0, dci->edac_dev_name); 1008 edac_device_handle_ce(dci->edac_dev, 0, 0, dci->edac_dev_name);
999 } else { 1009
1010 return IRQ_HANDLED;
1011 } else if (irq == dci->db_irq) {
1000 regmap_write(dci->edac->ecc_mgr_map, 1012 regmap_write(dci->edac->ecc_mgr_map,
1001 A10_SYSGMR_MPU_CLEAR_L2_ECC_OFST, 1013 A10_SYSGMR_MPU_CLEAR_L2_ECC_OFST,
1002 A10_SYSGMR_MPU_CLEAR_L2_ECC_MB); 1014 A10_SYSGMR_MPU_CLEAR_L2_ECC_MB);
1003 edac_device_handle_ue(dci->edac_dev, 0, 0, dci->edac_dev_name); 1015 edac_device_handle_ue(dci->edac_dev, 0, 0, dci->edac_dev_name);
1004 panic("\nEDAC:ECC_DEVICE[Uncorrectable errors]\n"); 1016 panic("\nEDAC:ECC_DEVICE[Uncorrectable errors]\n");
1017
1018 return IRQ_HANDLED;
1005 } 1019 }
1006 return IRQ_HANDLED; 1020
1021 WARN_ON(1);
1022
1023 return IRQ_NONE;
1007} 1024}
1008 1025
1009const struct edac_device_prv_data l2ecc_data = { 1026const struct edac_device_prv_data l2ecc_data = {
@@ -1075,28 +1092,28 @@ static ssize_t altr_edac_a10_device_trig(struct file *file,
1075 return count; 1092 return count;
1076} 1093}
1077 1094
1078static irqreturn_t altr_edac_a10_irq_handler(int irq, void *dev_id) 1095static void altr_edac_a10_irq_handler(struct irq_desc *desc)
1079{ 1096{
1080 irqreturn_t rc = IRQ_NONE; 1097 int dberr, bit, sm_offset, irq_status;
1081 struct altr_arria10_edac *edac = dev_id; 1098 struct altr_arria10_edac *edac = irq_desc_get_handler_data(desc);
1082 struct altr_edac_device_dev *dci; 1099 struct irq_chip *chip = irq_desc_get_chip(desc);
1083 int irq_status; 1100 int irq = irq_desc_get_irq(desc);
1084 bool sberr = (irq == edac->sb_irq) ? 1 : 0; 1101
1085 int sm_offset = sberr ? A10_SYSMGR_ECC_INTSTAT_SERR_OFST : 1102 dberr = (irq == edac->db_irq) ? 1 : 0;
1086 A10_SYSMGR_ECC_INTSTAT_DERR_OFST; 1103 sm_offset = dberr ? A10_SYSMGR_ECC_INTSTAT_DERR_OFST :
1104 A10_SYSMGR_ECC_INTSTAT_SERR_OFST;
1105
1106 chained_irq_enter(chip, desc);
1087 1107
1088 regmap_read(edac->ecc_mgr_map, sm_offset, &irq_status); 1108 regmap_read(edac->ecc_mgr_map, sm_offset, &irq_status);
1089 1109
1090 if ((irq != edac->sb_irq) && (irq != edac->db_irq)) { 1110 for_each_set_bit(bit, (unsigned long *)&irq_status, 32) {
1091 WARN_ON(1); 1111 irq = irq_linear_revmap(edac->domain, dberr * 32 + bit);
1092 } else { 1112 if (irq)
1093 list_for_each_entry(dci, &edac->a10_ecc_devices, next) { 1113 generic_handle_irq(irq);
1094 if (irq_status & dci->data->irq_status_mask)
1095 rc = dci->data->ecc_irq_handler(dci, sberr);
1096 }
1097 } 1114 }
1098 1115
1099 return rc; 1116 chained_irq_exit(chip, desc);
1100} 1117}
1101 1118
1102static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, 1119static int altr_edac_a10_device_add(struct altr_arria10_edac *edac,
@@ -1168,6 +1185,34 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac,
1168 goto err_release_group1; 1185 goto err_release_group1;
1169 } 1186 }
1170 1187
1188 altdev->sb_irq = irq_of_parse_and_map(np, 0);
1189 if (!altdev->sb_irq) {
1190 edac_printk(KERN_ERR, EDAC_DEVICE, "Error allocating SBIRQ\n");
1191 rc = -ENODEV;
1192 goto err_release_group1;
1193 }
1194 rc = devm_request_irq(edac->dev, altdev->sb_irq,
1195 prv->ecc_irq_handler,
1196 IRQF_SHARED, ecc_name, altdev);
1197 if (rc) {
1198 edac_printk(KERN_ERR, EDAC_DEVICE, "No DBERR IRQ resource\n");
1199 goto err_release_group1;
1200 }
1201
1202 altdev->db_irq = irq_of_parse_and_map(np, 1);
1203 if (!altdev->db_irq) {
1204 edac_printk(KERN_ERR, EDAC_DEVICE, "Error allocating DBIRQ\n");
1205 rc = -ENODEV;
1206 goto err_release_group1;
1207 }
1208 rc = devm_request_irq(edac->dev, altdev->db_irq,
1209 prv->ecc_irq_handler,
1210 IRQF_SHARED, ecc_name, altdev);
1211 if (rc) {
1212 edac_printk(KERN_ERR, EDAC_DEVICE, "No DBERR IRQ resource\n");
1213 goto err_release_group1;
1214 }
1215
1171 rc = edac_device_add_device(dci); 1216 rc = edac_device_add_device(dci);
1172 if (rc) { 1217 if (rc) {
1173 dev_err(edac->dev, "edac_device_add_device failed\n"); 1218 dev_err(edac->dev, "edac_device_add_device failed\n");
@@ -1186,7 +1231,6 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac,
1186err_release_group1: 1231err_release_group1:
1187 edac_device_free_ctl_info(dci); 1232 edac_device_free_ctl_info(dci);
1188err_release_group: 1233err_release_group:
1189 edac_printk(KERN_ALERT, EDAC_DEVICE, "%s: %d\n", __func__, __LINE__);
1190 devres_release_group(edac->dev, NULL); 1234 devres_release_group(edac->dev, NULL);
1191 edac_printk(KERN_ERR, EDAC_DEVICE, 1235 edac_printk(KERN_ERR, EDAC_DEVICE,
1192 "%s:Error setting up EDAC device: %d\n", ecc_name, rc); 1236 "%s:Error setting up EDAC device: %d\n", ecc_name, rc);
@@ -1194,11 +1238,43 @@ err_release_group:
1194 return rc; 1238 return rc;
1195} 1239}
1196 1240
1241static void a10_eccmgr_irq_mask(struct irq_data *d)
1242{
1243 struct altr_arria10_edac *edac = irq_data_get_irq_chip_data(d);
1244
1245 regmap_write(edac->ecc_mgr_map, A10_SYSMGR_ECC_INTMASK_SET_OFST,
1246 BIT(d->hwirq));
1247}
1248
1249static void a10_eccmgr_irq_unmask(struct irq_data *d)
1250{
1251 struct altr_arria10_edac *edac = irq_data_get_irq_chip_data(d);
1252
1253 regmap_write(edac->ecc_mgr_map, A10_SYSMGR_ECC_INTMASK_CLR_OFST,
1254 BIT(d->hwirq));
1255}
1256
1257static int a10_eccmgr_irqdomain_map(struct irq_domain *d, unsigned int irq,
1258 irq_hw_number_t hwirq)
1259{
1260 struct altr_arria10_edac *edac = d->host_data;
1261
1262 irq_set_chip_and_handler(irq, &edac->irq_chip, handle_simple_irq);
1263 irq_set_chip_data(irq, edac);
1264 irq_set_noprobe(irq);
1265
1266 return 0;
1267}
1268
1269struct irq_domain_ops a10_eccmgr_ic_ops = {
1270 .map = a10_eccmgr_irqdomain_map,
1271 .xlate = irq_domain_xlate_twocell,
1272};
1273
1197static int altr_edac_a10_probe(struct platform_device *pdev) 1274static int altr_edac_a10_probe(struct platform_device *pdev)
1198{ 1275{
1199 struct altr_arria10_edac *edac; 1276 struct altr_arria10_edac *edac;
1200 struct device_node *child; 1277 struct device_node *child;
1201 int rc;
1202 1278
1203 edac = devm_kzalloc(&pdev->dev, sizeof(*edac), GFP_KERNEL); 1279 edac = devm_kzalloc(&pdev->dev, sizeof(*edac), GFP_KERNEL);
1204 if (!edac) 1280 if (!edac)
@@ -1216,23 +1292,34 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
1216 return PTR_ERR(edac->ecc_mgr_map); 1292 return PTR_ERR(edac->ecc_mgr_map);
1217 } 1293 }
1218 1294
1295 edac->irq_chip.name = pdev->dev.of_node->name;
1296 edac->irq_chip.irq_mask = a10_eccmgr_irq_mask;
1297 edac->irq_chip.irq_unmask = a10_eccmgr_irq_unmask;
1298 edac->domain = irq_domain_add_linear(pdev->dev.of_node, 64,
1299 &a10_eccmgr_ic_ops, edac);
1300 if (!edac->domain) {
1301 dev_err(&pdev->dev, "Error adding IRQ domain\n");
1302 return -ENOMEM;
1303 }
1304
1219 edac->sb_irq = platform_get_irq(pdev, 0); 1305 edac->sb_irq = platform_get_irq(pdev, 0);
1220 rc = devm_request_irq(&pdev->dev, edac->sb_irq, 1306 if (edac->sb_irq < 0) {
1221 altr_edac_a10_irq_handler, 1307 dev_err(&pdev->dev, "No SBERR IRQ resource\n");
1222 IRQF_SHARED, dev_name(&pdev->dev), edac); 1308 return edac->sb_irq;
1223 if (rc) {
1224 edac_printk(KERN_ERR, EDAC_DEVICE, "No SBERR IRQ resource\n");
1225 return rc;
1226 } 1309 }
1227 1310
1311 irq_set_chained_handler_and_data(edac->sb_irq,
1312 altr_edac_a10_irq_handler,
1313 edac);
1314
1228 edac->db_irq = platform_get_irq(pdev, 1); 1315 edac->db_irq = platform_get_irq(pdev, 1);
1229 rc = devm_request_irq(&pdev->dev, edac->db_irq, 1316 if (edac->db_irq < 0) {
1230 altr_edac_a10_irq_handler, 1317 dev_err(&pdev->dev, "No DBERR IRQ resource\n");
1231 IRQF_SHARED, dev_name(&pdev->dev), edac); 1318 return edac->db_irq;
1232 if (rc) {
1233 edac_printk(KERN_ERR, EDAC_DEVICE, "No DBERR IRQ resource\n");
1234 return rc;
1235 } 1319 }
1320 irq_set_chained_handler_and_data(edac->db_irq,
1321 altr_edac_a10_irq_handler,
1322 edac);
1236 1323
1237 for_each_child_of_node(pdev->dev.of_node, child) { 1324 for_each_child_of_node(pdev->dev.of_node, child) {
1238 if (!of_device_is_available(child)) 1325 if (!of_device_is_available(child))
diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h
index 42090f36ba6e..62b0fa010f95 100644
--- a/drivers/edac/altera_edac.h
+++ b/drivers/edac/altera_edac.h
@@ -295,8 +295,7 @@ struct edac_device_prv_data {
295 int ce_set_mask; 295 int ce_set_mask;
296 int ue_set_mask; 296 int ue_set_mask;
297 int set_err_ofst; 297 int set_err_ofst;
298 irqreturn_t (*ecc_irq_handler)(struct altr_edac_device_dev *dci, 298 irqreturn_t (*ecc_irq_handler)(int irq, void *dev_id);
299 bool sb);
300 int trig_alloc_sz; 299 int trig_alloc_sz;
301 const struct file_operations *inject_fops; 300 const struct file_operations *inject_fops;
302}; 301};
@@ -320,6 +319,8 @@ struct altr_arria10_edac {
320 struct regmap *ecc_mgr_map; 319 struct regmap *ecc_mgr_map;
321 int sb_irq; 320 int sb_irq;
322 int db_irq; 321 int db_irq;
322 struct irq_domain *domain;
323 struct irq_chip irq_chip;
323 struct list_head a10_ecc_devices; 324 struct list_head a10_ecc_devices;
324}; 325};
325 326