summaryrefslogtreecommitdiff
path: root/drivers/edac
diff options
context:
space:
mode:
authorManivannan Sadhasivam <manivannan.sadhasivam@linaro.org>2023-03-14 11:04:42 +0300
committerBjorn Andersson <andersson@kernel.org>2023-03-16 01:17:08 +0300
commit721d3e91bfc93975c5e1a76c7d588dd8df5d82da (patch)
tree42c67c927b26802884d00d939a906a1c746e4d85 /drivers/edac
parentee13b5008707948d3052c1b5aab485c6cd53658e (diff)
downloadlinux-721d3e91bfc93975c5e1a76c7d588dd8df5d82da.tar.xz
qcom: llcc/edac: Support polling mode for ECC handling
Not all Qcom platforms support IRQ mode for ECC handling. For those platforms, the current EDAC driver will not be probed due to missing ECC IRQ in devicetree. So add support for polling mode so that the EDAC driver can be used on all Qcom platforms supporting LLCC. The polling delay of 5000ms is chosen based on Qcom downstream/vendor driver. Reported-by: Luca Weiss <luca.weiss@fairphone.com> Tested-by: Luca Weiss <luca.weiss@fairphone.com> Tested-by: Steev Klimaszewski <steev@kali.org> # Thinkpad X13s Tested-by: Andrew Halaney <ahalaney@redhat.com> # sa8540p-ride Reviewed-by: Borislav Petkov (AMD) <bp@alien8.de> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> Signed-off-by: Bjorn Andersson <andersson@kernel.org> Link: https://lore.kernel.org/r/20230314080443.64635-14-manivannan.sadhasivam@linaro.org
Diffstat (limited to 'drivers/edac')
-rw-r--r--drivers/edac/qcom_edac.c50
1 files changed, 29 insertions, 21 deletions
diff --git a/drivers/edac/qcom_edac.c b/drivers/edac/qcom_edac.c
index 1d3cc1930a74..265e0fb39bc7 100644
--- a/drivers/edac/qcom_edac.c
+++ b/drivers/edac/qcom_edac.c
@@ -76,6 +76,8 @@
#define DRP0_INTERRUPT_ENABLE BIT(6)
#define SB_DB_DRP_INTERRUPT_ENABLE 0x3
+#define ECC_POLL_MSEC 5000
+
enum {
LLCC_DRAM_CE = 0,
LLCC_DRAM_UE,
@@ -283,8 +285,7 @@ dump_syn_reg(struct edac_device_ctl_info *edev_ctl, int err_type, u32 bank)
return ret;
}
-static irqreturn_t
-llcc_ecc_irq_handler(int irq, void *edev_ctl)
+static irqreturn_t llcc_ecc_irq_handler(int irq, void *edev_ctl)
{
struct edac_device_ctl_info *edac_dev_ctl = edev_ctl;
struct llcc_drv_data *drv = edac_dev_ctl->dev->platform_data;
@@ -328,6 +329,11 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl)
return irq_rc;
}
+static void llcc_ecc_check(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;
@@ -355,29 +361,31 @@ static int qcom_llcc_edac_probe(struct platform_device *pdev)
edev_ctl->ctl_name = "llcc";
edev_ctl->panic_on_ue = LLCC_ERP_PANIC_ON_UE;
- rc = edac_device_add_device(edev_ctl);
- if (rc)
- goto out_mem;
-
- platform_set_drvdata(pdev, edev_ctl);
-
- /* Request for ecc irq */
+ /* Check if LLCC driver has passed 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,
+ if (ecc_irq > 0) {
+ /* Use interrupt mode if IRQ is available */
+ rc = devm_request_irq(dev, ecc_irq, llcc_ecc_irq_handler,
IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl);
- if (rc)
- goto out_dev;
+ if (!rc) {
+ edac_op_state = EDAC_OPSTATE_INT;
+ goto irq_done;
+ }
+ }
- return rc;
+ /* Fall back to polling mode otherwise */
+ edev_ctl->poll_msec = ECC_POLL_MSEC;
+ edev_ctl->edac_check = llcc_ecc_check;
+ edac_op_state = EDAC_OPSTATE_POLL;
-out_dev:
- edac_device_del_device(edev_ctl->dev);
-out_mem:
- edac_device_free_ctl_info(edev_ctl);
+irq_done:
+ rc = edac_device_add_device(edev_ctl);
+ if (rc) {
+ edac_device_free_ctl_info(edev_ctl);
+ return rc;
+ }
+
+ platform_set_drvdata(pdev, edev_ctl);
return rc;
}