diff options
| -rw-r--r-- | drivers/edac/altera_edac.c | 67 | ||||
| -rw-r--r-- | drivers/edac/altera_edac.h | 8 |
2 files changed, 64 insertions, 11 deletions
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 0ee6d5969ef2..1f12fdf2ed00 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <linux/irqchip/chained_irq.h> | 14 | #include <linux/irqchip/chained_irq.h> |
| 15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 16 | #include <linux/mfd/syscon.h> | 16 | #include <linux/mfd/syscon.h> |
| 17 | #include <linux/notifier.h> | ||
| 17 | #include <linux/of_address.h> | 18 | #include <linux/of_address.h> |
| 18 | #include <linux/of_irq.h> | 19 | #include <linux/of_irq.h> |
| 19 | #include <linux/of_platform.h> | 20 | #include <linux/of_platform.h> |
| @@ -725,6 +726,13 @@ static int altr_s10_sdram_probe(struct platform_device *pdev) | |||
| 725 | goto err2; | 726 | goto err2; |
| 726 | } | 727 | } |
| 727 | 728 | ||
| 729 | if (regmap_write(regmap, S10_SYSMGR_ECC_INTMASK_CLR_OFST, | ||
| 730 | S10_DDR0_IRQ_MASK)) { | ||
| 731 | edac_printk(KERN_ERR, EDAC_MC, | ||
| 732 | "Error clearing SDRAM ECC count\n"); | ||
| 733 | return -ENODEV; | ||
| 734 | } | ||
| 735 | |||
| 728 | if (regmap_update_bits(drvdata->mc_vbase, priv->ecc_irq_en_offset, | 736 | if (regmap_update_bits(drvdata->mc_vbase, priv->ecc_irq_en_offset, |
| 729 | priv->ecc_irq_en_mask, priv->ecc_irq_en_mask)) { | 737 | priv->ecc_irq_en_mask, priv->ecc_irq_en_mask)) { |
| 730 | edac_mc_printk(mci, KERN_ERR, | 738 | edac_mc_printk(mci, KERN_ERR, |
| @@ -2228,23 +2236,50 @@ module_platform_driver(altr_edac_a10_driver); | |||
| 2228 | 2236 | ||
| 2229 | /************** Stratix 10 EDAC Device Controller Functions> ************/ | 2237 | /************** Stratix 10 EDAC Device Controller Functions> ************/ |
| 2230 | 2238 | ||
| 2239 | #define to_s10edac(p, m) container_of(p, struct altr_stratix10_edac, m) | ||
| 2240 | |||
| 2241 | /* | ||
| 2242 | * The double bit error is handled through SError which is fatal. This is | ||
| 2243 | * called as a panic notifier to printout ECC error info as part of the panic. | ||
| 2244 | */ | ||
| 2245 | static int s10_edac_dberr_handler(struct notifier_block *this, | ||
| 2246 | unsigned long event, void *ptr) | ||
| 2247 | { | ||
| 2248 | struct altr_stratix10_edac *edac = to_s10edac(this, panic_notifier); | ||
| 2249 | int err_addr, dberror; | ||
| 2250 | |||
| 2251 | s10_protected_reg_read(edac, S10_SYSMGR_ECC_INTSTAT_DERR_OFST, | ||
| 2252 | &dberror); | ||
| 2253 | /* Remember the UE Errors for a reboot */ | ||
| 2254 | s10_protected_reg_write(edac, S10_SYSMGR_UE_VAL_OFST, dberror); | ||
| 2255 | if (dberror & S10_DDR0_IRQ_MASK) { | ||
| 2256 | s10_protected_reg_read(edac, S10_DERRADDR_OFST, &err_addr); | ||
| 2257 | /* Remember the UE Error address */ | ||
| 2258 | s10_protected_reg_write(edac, S10_SYSMGR_UE_ADDR_OFST, | ||
| 2259 | err_addr); | ||
| 2260 | edac_printk(KERN_ERR, EDAC_MC, | ||
| 2261 | "EDAC: [Uncorrectable errors @ 0x%08X]\n\n", | ||
| 2262 | err_addr); | ||
| 2263 | } | ||
| 2264 | |||
| 2265 | return NOTIFY_DONE; | ||
| 2266 | } | ||
| 2267 | |||
| 2231 | static void altr_edac_s10_irq_handler(struct irq_desc *desc) | 2268 | static void altr_edac_s10_irq_handler(struct irq_desc *desc) |
| 2232 | { | 2269 | { |
| 2233 | int dberr, bit, sm_offset, irq_status; | ||
| 2234 | struct altr_stratix10_edac *edac = irq_desc_get_handler_data(desc); | 2270 | struct altr_stratix10_edac *edac = irq_desc_get_handler_data(desc); |
| 2235 | struct irq_chip *chip = irq_desc_get_chip(desc); | 2271 | struct irq_chip *chip = irq_desc_get_chip(desc); |
| 2236 | int irq = irq_desc_get_irq(desc); | 2272 | int irq = irq_desc_get_irq(desc); |
| 2273 | int bit, sm_offset, irq_status; | ||
| 2237 | 2274 | ||
| 2238 | dberr = (irq == edac->db_irq) ? 1 : 0; | 2275 | sm_offset = S10_SYSMGR_ECC_INTSTAT_SERR_OFST; |
| 2239 | sm_offset = dberr ? S10_SYSMGR_ECC_INTSTAT_DERR_OFST : | ||
| 2240 | S10_SYSMGR_ECC_INTSTAT_SERR_OFST; | ||
| 2241 | 2276 | ||
| 2242 | chained_irq_enter(chip, desc); | 2277 | chained_irq_enter(chip, desc); |
| 2243 | 2278 | ||
| 2244 | s10_protected_reg_read(NULL, sm_offset, &irq_status); | 2279 | s10_protected_reg_read(NULL, sm_offset, &irq_status); |
| 2245 | 2280 | ||
| 2246 | for_each_set_bit(bit, (unsigned long *)&irq_status, 32) { | 2281 | for_each_set_bit(bit, (unsigned long *)&irq_status, 32) { |
| 2247 | irq = irq_linear_revmap(edac->domain, dberr * 32 + bit); | 2282 | irq = irq_linear_revmap(edac->domain, bit); |
| 2248 | if (irq) | 2283 | if (irq) |
| 2249 | generic_handle_irq(irq); | 2284 | generic_handle_irq(irq); |
| 2250 | } | 2285 | } |
| @@ -2289,6 +2324,7 @@ static int altr_edac_s10_probe(struct platform_device *pdev) | |||
| 2289 | { | 2324 | { |
| 2290 | struct altr_stratix10_edac *edac; | 2325 | struct altr_stratix10_edac *edac; |
| 2291 | struct device_node *child; | 2326 | struct device_node *child; |
| 2327 | int dberror, err_addr; | ||
| 2292 | 2328 | ||
| 2293 | edac = devm_kzalloc(&pdev->dev, sizeof(*edac), GFP_KERNEL); | 2329 | edac = devm_kzalloc(&pdev->dev, sizeof(*edac), GFP_KERNEL); |
| 2294 | if (!edac) | 2330 | if (!edac) |
| @@ -2318,11 +2354,22 @@ static int altr_edac_s10_probe(struct platform_device *pdev) | |||
| 2318 | altr_edac_s10_irq_handler, | 2354 | altr_edac_s10_irq_handler, |
| 2319 | edac); | 2355 | edac); |
| 2320 | 2356 | ||
| 2321 | edac->db_irq = platform_get_irq(pdev, 1); | 2357 | edac->panic_notifier.notifier_call = s10_edac_dberr_handler; |
| 2322 | if (edac->db_irq >= 0) | 2358 | atomic_notifier_chain_register(&panic_notifier_list, |
| 2323 | irq_set_chained_handler_and_data(edac->db_irq, | 2359 | &edac->panic_notifier); |
| 2324 | altr_edac_s10_irq_handler, | 2360 | |
| 2325 | edac); | 2361 | /* Printout a message if uncorrectable error previously. */ |
| 2362 | s10_protected_reg_read(edac, S10_SYSMGR_UE_VAL_OFST, &dberror); | ||
| 2363 | if (dberror) { | ||
| 2364 | s10_protected_reg_read(edac, S10_SYSMGR_UE_ADDR_OFST, | ||
| 2365 | &err_addr); | ||
| 2366 | edac_printk(KERN_ERR, EDAC_DEVICE, | ||
| 2367 | "Previous Boot UE detected[0x%X] @ 0x%X\n", | ||
| 2368 | dberror, err_addr); | ||
| 2369 | /* Reset the sticky registers */ | ||
| 2370 | s10_protected_reg_write(edac, S10_SYSMGR_UE_VAL_OFST, 0); | ||
| 2371 | s10_protected_reg_write(edac, S10_SYSMGR_UE_ADDR_OFST, 0); | ||
| 2372 | } | ||
| 2326 | 2373 | ||
| 2327 | for_each_child_of_node(pdev->dev.of_node, child) { | 2374 | for_each_child_of_node(pdev->dev.of_node, child) { |
| 2328 | if (!of_device_is_available(child)) | 2375 | if (!of_device_is_available(child)) |
diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h index 747481081072..81f0554e09de 100644 --- a/drivers/edac/altera_edac.h +++ b/drivers/edac/altera_edac.h | |||
| @@ -180,6 +180,10 @@ | |||
| 180 | /* SDRAM Single Bit Error Count Compare Set Register */ | 180 | /* SDRAM Single Bit Error Count Compare Set Register */ |
| 181 | #define S10_SERRCNTREG_OFST 0xF801113C | 181 | #define S10_SERRCNTREG_OFST 0xF801113C |
| 182 | 182 | ||
| 183 | /* Sticky registers for Uncorrected Errors */ | ||
| 184 | #define S10_SYSMGR_UE_VAL_OFST 0xFFD12220 | ||
| 185 | #define S10_SYSMGR_UE_ADDR_OFST 0xFFD12224 | ||
| 186 | |||
| 183 | struct altr_sdram_prv_data { | 187 | struct altr_sdram_prv_data { |
| 184 | int ecc_ctrl_offset; | 188 | int ecc_ctrl_offset; |
| 185 | int ecc_ctl_en_mask; | 189 | int ecc_ctl_en_mask; |
| @@ -322,6 +326,8 @@ struct altr_sdram_mc_data { | |||
| 322 | #define S10_SYSMGR_ECC_INTSTAT_SERR_OFST 0xFFD1209C | 326 | #define S10_SYSMGR_ECC_INTSTAT_SERR_OFST 0xFFD1209C |
| 323 | #define S10_SYSMGR_ECC_INTSTAT_DERR_OFST 0xFFD120A0 | 327 | #define S10_SYSMGR_ECC_INTSTAT_DERR_OFST 0xFFD120A0 |
| 324 | 328 | ||
| 329 | #define S10_DDR0_IRQ_MASK BIT(16) | ||
| 330 | |||
| 325 | struct altr_edac_device_dev; | 331 | struct altr_edac_device_dev; |
| 326 | 332 | ||
| 327 | struct edac_device_prv_data { | 333 | struct edac_device_prv_data { |
| @@ -434,10 +440,10 @@ struct altr_arria10_edac { | |||
| 434 | struct altr_stratix10_edac { | 440 | struct altr_stratix10_edac { |
| 435 | struct device *dev; | 441 | struct device *dev; |
| 436 | int sb_irq; | 442 | int sb_irq; |
| 437 | int db_irq; | ||
| 438 | struct irq_domain *domain; | 443 | struct irq_domain *domain; |
| 439 | struct irq_chip irq_chip; | 444 | struct irq_chip irq_chip; |
| 440 | struct list_head s10_ecc_devices; | 445 | struct list_head s10_ecc_devices; |
| 446 | struct notifier_block panic_notifier; | ||
| 441 | }; | 447 | }; |
| 442 | 448 | ||
| 443 | #endif /* #ifndef _ALTERA_EDAC_H */ | 449 | #endif /* #ifndef _ALTERA_EDAC_H */ |
