qcom: llcc/edac: Support polling mode for ECC handling
[ Upstream commit 721d3e91bfc93975c5e1a76c7d588dd8df5d82da ] 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 Stable-dep-of: cca94f1dd6d0 ("soc: qcom: llcc: Do not create EDAC platform device on SDM845") Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
4fdb257b2a
commit
bf9712195f
@ -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,
|
||||
@ -285,8 +287,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;
|
||||
@ -332,6 +333,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;
|
||||
@ -359,30 +365,32 @@ 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;
|
||||
|
||||
/* Check if LLCC driver has passed ECC IRQ */
|
||||
ecc_irq = llcc_driv_data->ecc_irq;
|
||||
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) {
|
||||
edac_op_state = EDAC_OPSTATE_INT;
|
||||
goto irq_done;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
irq_done:
|
||||
rc = edac_device_add_device(edev_ctl);
|
||||
if (rc)
|
||||
goto out_mem;
|
||||
if (rc) {
|
||||
edac_device_free_ctl_info(edev_ctl);
|
||||
return rc;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, edev_ctl);
|
||||
|
||||
/* 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_TRIGGER_HIGH, "llcc_ecc", edev_ctl);
|
||||
if (rc)
|
||||
goto out_dev;
|
||||
|
||||
return rc;
|
||||
|
||||
out_dev:
|
||||
edac_device_del_device(edev_ctl->dev);
|
||||
out_mem:
|
||||
edac_device_free_ctl_info(edev_ctl);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -850,13 +850,12 @@ static int qcom_llcc_probe(struct platform_device *pdev)
|
||||
goto err;
|
||||
|
||||
drv_data->ecc_irq = platform_get_irq_optional(pdev, 0);
|
||||
if (drv_data->ecc_irq >= 0) {
|
||||
llcc_edac = platform_device_register_data(&pdev->dev,
|
||||
"qcom_llcc_edac", -1, drv_data,
|
||||
sizeof(*drv_data));
|
||||
if (IS_ERR(llcc_edac))
|
||||
dev_err(dev, "Failed to register llcc edac driver\n");
|
||||
}
|
||||
|
||||
llcc_edac = platform_device_register_data(&pdev->dev,
|
||||
"qcom_llcc_edac", -1, drv_data,
|
||||
sizeof(*drv_data));
|
||||
if (IS_ERR(llcc_edac))
|
||||
dev_err(dev, "Failed to register llcc edac driver\n");
|
||||
|
||||
return 0;
|
||||
err:
|
||||
|
Loading…
Reference in New Issue
Block a user