Loading drivers/edac/Kconfig +23 −0 Original line number Diff line number Diff line Loading @@ -550,6 +550,29 @@ config EDAC_QCOM For debugging issues having to do with stability and overall system health, you should probably say 'Y' here. config EDAC_QCOM_LLCC_PANIC_ON_CE depends on EDAC_QCOM select EDAC_PANIC_ON_CE bool "panic on correctable errors - qcom llcc" help Forcibly cause kernel panic if a correctable error (CE) is detected, even though the error is (by definition) correctable and would otherwise result in no adverse system effects. This can reduce debugging times on hardware which my be operating at voltages or frequencies outside normal specifications. For production builds, you should definitely say 'N' here. config EDAC_QCOM_LLCC_PANIC_ON_UE depends on EDAC_QCOM bool "Panic on uncorrectable errors - qcom llcc" help Forcibly cause a kernel panic if an uncorrectable error (UE) is detected. This can reduce debugging times on hardware which may be operating at voltages or frequencies outside normal specification. For production builds, you should probably say 'N' here. config EDAC_ASPEED tristate "Aspeed AST 2500 SoC" depends on MACH_ASPEED_G5 Loading drivers/edac/qcom_edac.c +44 −20 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018, The Linux Foundation. All rights reserved. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */ #include <linux/edac.h> Loading @@ -16,7 +16,13 @@ #define EDAC_LLCC "qcom_llcc" #define LLCC_ERP_PANIC_ON_CE 1 #ifdef CONFIG_EDAC_QCOM_LLCC_PANIC_ON_UE #define LLCC_ERP_PANIC_ON_UE 1 #else #define LLCC_ERP_PANIC_ON_UE 0 #endif #define TRP_SYN_REG_CNT 6 #define DRP_SYN_REG_CNT 8 Loading @@ -26,7 +32,7 @@ #define LLCC_LB_CNT_SHIFT 28 /* Single & double bit syndrome register offsets */ #define TRP_ECC_SB_ERR_SYN0 0x0002304c #define TRP_ECC_SB_ERR_SYN0 0x0002034c #define TRP_ECC_DB_ERR_SYN0 0x00020370 #define DRP_ECC_SB_ERR_SYN0 0x0004204c #define DRP_ECC_DB_ERR_SYN0 0x00042070 Loading Loading @@ -76,6 +82,9 @@ #define DRP0_INTERRUPT_ENABLE BIT(6) #define SB_DB_DRP_INTERRUPT_ENABLE 0x3 static int poll_msec = 5000; module_param(poll_msec, int, 0444); enum { LLCC_DRAM_CE = 0, LLCC_DRAM_UE, Loading Loading @@ -292,6 +301,7 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl) struct llcc_drv_data *drv = edac_dev_ctl->pvt_info; irqreturn_t irq_rc = IRQ_NONE; u32 drp_error, trp_error, i; bool irq_handled = false; int ret; /* Iterate over the banks and look for Tag RAM or Data RAM errors */ Loading @@ -310,7 +320,7 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl) ret = dump_syn_reg(edev_ctl, LLCC_DRAM_UE, i); } if (!ret) irq_rc = IRQ_HANDLED; irq_handled = true; ret = regmap_read(drv->regmap, drv->offsets[i] + TRP_INTERRUPT_0_STATUS, Loading @@ -326,12 +336,20 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl) ret = dump_syn_reg(edev_ctl, LLCC_TRAM_UE, i); } if (!ret) irq_rc = IRQ_HANDLED; irq_handled = true; } if (irq_handled) irq_rc = IRQ_HANDLED; return irq_rc; } static void qcom_llcc_poll_cache_errors(struct edac_device_ctl_info *edev_ctl) { llcc_ecc_irq_handler(0, edev_ctl); } static int qcom_llcc_edac_probe(struct platform_device *pdev) { struct llcc_drv_data *llcc_driv_data = pdev->dev.platform_data; Loading @@ -340,10 +358,6 @@ static int qcom_llcc_edac_probe(struct platform_device *pdev) int ecc_irq; int rc; rc = qcom_llcc_core_setup(llcc_driv_data->bcast_regmap); if (rc) return rc; /* Allocate edac control info */ edev_ctl = edac_device_alloc_ctl_info(0, "qcom-llcc", 1, "bank", llcc_driv_data->num_banks, 1, Loading @@ -358,32 +372,42 @@ static int qcom_llcc_edac_probe(struct platform_device *pdev) edev_ctl->dev_name = dev_name(dev); edev_ctl->ctl_name = "llcc"; edev_ctl->panic_on_ue = LLCC_ERP_PANIC_ON_UE; #ifdef CONFIG_EDAC_QCOM_LLCC_PANIC_ON_CE edev_ctl->panic_on_ce = LLCC_ERP_PANIC_ON_CE; #endif edev_ctl->pvt_info = llcc_driv_data; /* Request for ecc irq */ ecc_irq = llcc_driv_data->ecc_irq; if (ecc_irq < 0) { dev_info(dev, "No ECC IRQ; defaulting to polling mode\n"); edev_ctl->poll_msec = poll_msec; edev_ctl->edac_check = qcom_llcc_poll_cache_errors; } rc = edac_device_add_device(edev_ctl); if (rc) goto out_mem; platform_set_drvdata(pdev, edev_ctl); /* Request for ecc irq */ ecc_irq = llcc_driv_data->ecc_irq; if (ecc_irq < 0) { rc = -ENODEV; if (ecc_irq >= 0) { rc = qcom_llcc_core_setup(llcc_driv_data->bcast_regmap); if (rc) goto out_dev; } rc = devm_request_irq(dev, ecc_irq, llcc_ecc_irq_handler, IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl); IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl); if (rc) goto out_dev; } platform_set_drvdata(pdev, edev_ctl); return rc; out_dev: edac_device_del_device(edev_ctl->dev); out_mem: edac_device_free_ctl_info(edev_ctl); return rc; } Loading Loading
drivers/edac/Kconfig +23 −0 Original line number Diff line number Diff line Loading @@ -550,6 +550,29 @@ config EDAC_QCOM For debugging issues having to do with stability and overall system health, you should probably say 'Y' here. config EDAC_QCOM_LLCC_PANIC_ON_CE depends on EDAC_QCOM select EDAC_PANIC_ON_CE bool "panic on correctable errors - qcom llcc" help Forcibly cause kernel panic if a correctable error (CE) is detected, even though the error is (by definition) correctable and would otherwise result in no adverse system effects. This can reduce debugging times on hardware which my be operating at voltages or frequencies outside normal specifications. For production builds, you should definitely say 'N' here. config EDAC_QCOM_LLCC_PANIC_ON_UE depends on EDAC_QCOM bool "Panic on uncorrectable errors - qcom llcc" help Forcibly cause a kernel panic if an uncorrectable error (UE) is detected. This can reduce debugging times on hardware which may be operating at voltages or frequencies outside normal specification. For production builds, you should probably say 'N' here. config EDAC_ASPEED tristate "Aspeed AST 2500 SoC" depends on MACH_ASPEED_G5 Loading
drivers/edac/qcom_edac.c +44 −20 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018, The Linux Foundation. All rights reserved. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */ #include <linux/edac.h> Loading @@ -16,7 +16,13 @@ #define EDAC_LLCC "qcom_llcc" #define LLCC_ERP_PANIC_ON_CE 1 #ifdef CONFIG_EDAC_QCOM_LLCC_PANIC_ON_UE #define LLCC_ERP_PANIC_ON_UE 1 #else #define LLCC_ERP_PANIC_ON_UE 0 #endif #define TRP_SYN_REG_CNT 6 #define DRP_SYN_REG_CNT 8 Loading @@ -26,7 +32,7 @@ #define LLCC_LB_CNT_SHIFT 28 /* Single & double bit syndrome register offsets */ #define TRP_ECC_SB_ERR_SYN0 0x0002304c #define TRP_ECC_SB_ERR_SYN0 0x0002034c #define TRP_ECC_DB_ERR_SYN0 0x00020370 #define DRP_ECC_SB_ERR_SYN0 0x0004204c #define DRP_ECC_DB_ERR_SYN0 0x00042070 Loading Loading @@ -76,6 +82,9 @@ #define DRP0_INTERRUPT_ENABLE BIT(6) #define SB_DB_DRP_INTERRUPT_ENABLE 0x3 static int poll_msec = 5000; module_param(poll_msec, int, 0444); enum { LLCC_DRAM_CE = 0, LLCC_DRAM_UE, Loading Loading @@ -292,6 +301,7 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl) struct llcc_drv_data *drv = edac_dev_ctl->pvt_info; irqreturn_t irq_rc = IRQ_NONE; u32 drp_error, trp_error, i; bool irq_handled = false; int ret; /* Iterate over the banks and look for Tag RAM or Data RAM errors */ Loading @@ -310,7 +320,7 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl) ret = dump_syn_reg(edev_ctl, LLCC_DRAM_UE, i); } if (!ret) irq_rc = IRQ_HANDLED; irq_handled = true; ret = regmap_read(drv->regmap, drv->offsets[i] + TRP_INTERRUPT_0_STATUS, Loading @@ -326,12 +336,20 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl) ret = dump_syn_reg(edev_ctl, LLCC_TRAM_UE, i); } if (!ret) irq_rc = IRQ_HANDLED; irq_handled = true; } if (irq_handled) irq_rc = IRQ_HANDLED; return irq_rc; } static void qcom_llcc_poll_cache_errors(struct edac_device_ctl_info *edev_ctl) { llcc_ecc_irq_handler(0, edev_ctl); } static int qcom_llcc_edac_probe(struct platform_device *pdev) { struct llcc_drv_data *llcc_driv_data = pdev->dev.platform_data; Loading @@ -340,10 +358,6 @@ static int qcom_llcc_edac_probe(struct platform_device *pdev) int ecc_irq; int rc; rc = qcom_llcc_core_setup(llcc_driv_data->bcast_regmap); if (rc) return rc; /* Allocate edac control info */ edev_ctl = edac_device_alloc_ctl_info(0, "qcom-llcc", 1, "bank", llcc_driv_data->num_banks, 1, Loading @@ -358,32 +372,42 @@ static int qcom_llcc_edac_probe(struct platform_device *pdev) edev_ctl->dev_name = dev_name(dev); edev_ctl->ctl_name = "llcc"; edev_ctl->panic_on_ue = LLCC_ERP_PANIC_ON_UE; #ifdef CONFIG_EDAC_QCOM_LLCC_PANIC_ON_CE edev_ctl->panic_on_ce = LLCC_ERP_PANIC_ON_CE; #endif edev_ctl->pvt_info = llcc_driv_data; /* Request for ecc irq */ ecc_irq = llcc_driv_data->ecc_irq; if (ecc_irq < 0) { dev_info(dev, "No ECC IRQ; defaulting to polling mode\n"); edev_ctl->poll_msec = poll_msec; edev_ctl->edac_check = qcom_llcc_poll_cache_errors; } rc = edac_device_add_device(edev_ctl); if (rc) goto out_mem; platform_set_drvdata(pdev, edev_ctl); /* Request for ecc irq */ ecc_irq = llcc_driv_data->ecc_irq; if (ecc_irq < 0) { rc = -ENODEV; if (ecc_irq >= 0) { rc = qcom_llcc_core_setup(llcc_driv_data->bcast_regmap); if (rc) goto out_dev; } rc = devm_request_irq(dev, ecc_irq, llcc_ecc_irq_handler, IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl); IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl); if (rc) goto out_dev; } platform_set_drvdata(pdev, edev_ctl); return rc; out_dev: edac_device_del_device(edev_ctl->dev); out_mem: edac_device_free_ctl_info(edev_ctl); return rc; } Loading