Commit 721d3e91 authored by Manivannan Sadhasivam's avatar Manivannan Sadhasivam Committed by Bjorn Andersson

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: default avatarLuca Weiss <luca.weiss@fairphone.com>
Tested-by: default avatarLuca 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: default avatarBorislav Petkov (AMD) <bp@alien8.de>
Signed-off-by: default avatarManivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: default avatarBjorn Andersson <andersson@kernel.org>
Link: https://lore.kernel.org/r/20230314080443.64635-14-manivannan.sadhasivam@linaro.org
parent ee13b500
...@@ -76,6 +76,8 @@ ...@@ -76,6 +76,8 @@
#define DRP0_INTERRUPT_ENABLE BIT(6) #define DRP0_INTERRUPT_ENABLE BIT(6)
#define SB_DB_DRP_INTERRUPT_ENABLE 0x3 #define SB_DB_DRP_INTERRUPT_ENABLE 0x3
#define ECC_POLL_MSEC 5000
enum { enum {
LLCC_DRAM_CE = 0, LLCC_DRAM_CE = 0,
LLCC_DRAM_UE, LLCC_DRAM_UE,
...@@ -283,8 +285,7 @@ dump_syn_reg(struct edac_device_ctl_info *edev_ctl, int err_type, u32 bank) ...@@ -283,8 +285,7 @@ dump_syn_reg(struct edac_device_ctl_info *edev_ctl, int err_type, u32 bank)
return ret; return ret;
} }
static irqreturn_t static irqreturn_t llcc_ecc_irq_handler(int irq, void *edev_ctl)
llcc_ecc_irq_handler(int irq, void *edev_ctl)
{ {
struct edac_device_ctl_info *edac_dev_ctl = edev_ctl; struct edac_device_ctl_info *edac_dev_ctl = edev_ctl;
struct llcc_drv_data *drv = edac_dev_ctl->dev->platform_data; struct llcc_drv_data *drv = edac_dev_ctl->dev->platform_data;
...@@ -328,6 +329,11 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl) ...@@ -328,6 +329,11 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl)
return irq_rc; 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) static int qcom_llcc_edac_probe(struct platform_device *pdev)
{ {
struct llcc_drv_data *llcc_driv_data = pdev->dev.platform_data; 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) ...@@ -355,29 +361,31 @@ static int qcom_llcc_edac_probe(struct platform_device *pdev)
edev_ctl->ctl_name = "llcc"; edev_ctl->ctl_name = "llcc";
edev_ctl->panic_on_ue = LLCC_ERP_PANIC_ON_UE; edev_ctl->panic_on_ue = LLCC_ERP_PANIC_ON_UE;
rc = edac_device_add_device(edev_ctl); /* Check if LLCC driver has passed ECC IRQ */
if (rc)
goto out_mem;
platform_set_drvdata(pdev, edev_ctl);
/* Request for ecc irq */
ecc_irq = llcc_driv_data->ecc_irq; ecc_irq = llcc_driv_data->ecc_irq;
if (ecc_irq < 0) { if (ecc_irq > 0) {
rc = -ENODEV; /* Use interrupt mode if IRQ is available */
goto out_dev; rc = devm_request_irq(dev, ecc_irq, llcc_ecc_irq_handler,
}
rc = devm_request_irq(dev, ecc_irq, llcc_ecc_irq_handler,
IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl); IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl);
if (rc) if (!rc) {
goto out_dev; 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: irq_done:
edac_device_del_device(edev_ctl->dev); rc = edac_device_add_device(edev_ctl);
out_mem: if (rc) {
edac_device_free_ctl_info(edev_ctl); edac_device_free_ctl_info(edev_ctl);
return rc;
}
platform_set_drvdata(pdev, edev_ctl);
return rc; return rc;
} }
......
...@@ -1011,13 +1011,12 @@ static int qcom_llcc_probe(struct platform_device *pdev) ...@@ -1011,13 +1011,12 @@ static int qcom_llcc_probe(struct platform_device *pdev)
goto err; goto err;
drv_data->ecc_irq = platform_get_irq_optional(pdev, 0); drv_data->ecc_irq = platform_get_irq_optional(pdev, 0);
if (drv_data->ecc_irq >= 0) {
llcc_edac = platform_device_register_data(&pdev->dev, llcc_edac = platform_device_register_data(&pdev->dev,
"qcom_llcc_edac", -1, drv_data, "qcom_llcc_edac", -1, drv_data,
sizeof(*drv_data)); sizeof(*drv_data));
if (IS_ERR(llcc_edac)) if (IS_ERR(llcc_edac))
dev_err(dev, "Failed to register llcc edac driver\n"); dev_err(dev, "Failed to register llcc edac driver\n");
}
return 0; return 0;
err: err:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment