Skip to content

Commit

Permalink
qcom: llcc/edac: Support polling mode for ECC handling
Browse files Browse the repository at this point in the history
[ Upstream commit 721d3e9 ]

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: cca94f1 ("soc: qcom: llcc: Do not create EDAC platform device on SDM845")
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Mani-Sadhasivam authored and gregkh committed May 17, 2023
1 parent 4fdb257 commit bf97121
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 28 deletions.
50 changes: 29 additions & 21 deletions drivers/edac/qcom_edac.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -359,29 +365,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;
}
Expand Down
13 changes: 6 additions & 7 deletions drivers/soc/qcom/llcc-qcom.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down

0 comments on commit bf97121

Please sign in to comment.