Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1e336131 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drivers: llcc edac: Add Cache Error Reporting driver for llcc"

parents a11cd8cd d3163721
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -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
+44 −20
Original line number Diff line number Diff line
// 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 <linux/edac.h>
@@ -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);

	/* Request for ecc irq */
	ecc_irq = llcc_driv_data->ecc_irq;
	if (ecc_irq < 0) {
		rc = -ENODEV;
	if (ecc_irq >= 0) {
		rc = qcom_llcc_core_setup(llcc_driv_data->bcast_regmap);
		if (rc)
			goto out_dev;
	}

		rc = devm_request_irq(dev, ecc_irq, llcc_ecc_irq_handler,
			      IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl);
			      IRQF_SHARED | IRQF_ONESHOT | 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;
}