From d316372155e7546bde40b968a231bd95b868d52e Mon Sep 17 00:00:00 2001 From: Murali Nalajala Date: Mon, 30 Sep 2019 13:24:11 -0700 Subject: [PATCH] drivers: llcc edac: Add Cache Error Reporting driver for llcc This is a snapshot of llcc cache error reporting driver for lahaina as of msm-4.19 commit. Convert the llcc edac drivers to compile as modules. Change-Id: I4b0da39975dbda7bbce9625455fc34c0a97a7c53 Signed-off-by: Murali Nalajala --- drivers/edac/Kconfig | 23 +++++++++++++++ drivers/edac/qcom_edac.c | 64 +++++++++++++++++++++++++++------------- 2 files changed, 67 insertions(+), 20 deletions(-) diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 5aface8d6574..a47e6082d66d 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -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 diff --git a/drivers/edac/qcom_edac.c b/drivers/edac/qcom_edac.c index 97a27e42dd61..e214f3713225 100644 --- a/drivers/edac/qcom_edac.c +++ b/drivers/edac/qcom_edac.c @@ -1,6 +1,6 @@ -// 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 @@ -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 @@ -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 @@ -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, @@ -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 */ @@ -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, @@ -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; @@ -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, @@ -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); + if (ecc_irq >= 0) { + rc = qcom_llcc_core_setup(llcc_driv_data->bcast_regmap); + if (rc) + goto out_dev; - /* Request for ecc irq */ - ecc_irq = llcc_driv_data->ecc_irq; - if (ecc_irq < 0) { - rc = -ENODEV; - goto out_dev; + rc = devm_request_irq(dev, ecc_irq, llcc_ecc_irq_handler, + IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_HIGH, + "llcc_ecc", edev_ctl); + if (rc) + goto out_dev; } - rc = devm_request_irq(dev, ecc_irq, llcc_ecc_irq_handler, - 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; }