drivers: edac: Update the register offsets
Update the register offsets as per the SW interface document. And use
the pvt_info member of edev structure to store the platform device
private data so that the cache error poll function can access the
private data without container_of macro. Update the Kconfig dependency
to make llcc edac driver on llcc core driver.
Change-Id: I66a8dbcfb7bcec98e81a2cb33026d9396f89da63
Signed-off-by: Channagoud Kadabi <ckadabi@codeaurora.org>
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 5ff5679..fb02626 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -462,7 +462,7 @@
APM X-Gene family of SOCs.
config EDAC_QCOM_LLCC
- depends on EDAC_MM_EDAC
+ depends on EDAC_MM_EDAC && QCOM_LLCC
tristate "QCOM LLCC Caches"
help
Support for error detection and correction on the
diff --git a/drivers/edac/qcom_llcc_edac.c b/drivers/edac/qcom_llcc_edac.c
index f123868..71f74ad 100644
--- a/drivers/edac/qcom_llcc_edac.c
+++ b/drivers/edac/qcom_llcc_edac.c
@@ -39,27 +39,27 @@
#define DRP_SYN_REG_CNT 8
/* single & Double Bit syndrome register offsets */
-#define TRP_ECC_SB_ERR_SYN0 0x0002334c
-#define TRP_ECC_DB_ERR_SYN0 0x00023370
-#define DRP_ECC_SB_ERR_SYN0 0x000400A8
-#define DRP_ECC_DB_ERR_SYN0 0x000400D0
+#define TRP_ECC_SB_ERR_SYN0 0x0002304C
+#define TRP_ECC_DB_ERR_SYN0 0x00020370
+#define DRP_ECC_SB_ERR_SYN0 0x0004204C
+#define DRP_ECC_DB_ERR_SYN0 0x00042070
/* Error register offsets */
-#define TRP_ECC_ERROR_STATUS1 0x00023348
-#define TRP_ECC_ERROR_STATUS0 0x00023344
-#define DRP_ECC_ERROR_STATUS1 0x000400A4
-#define DRP_ECC_ERROR_STATUS0 0x000400A0
+#define TRP_ECC_ERROR_STATUS1 0x00020348
+#define TRP_ECC_ERROR_STATUS0 0x00020344
+#define DRP_ECC_ERROR_STATUS1 0x00042048
+#define DRP_ECC_ERROR_STATUS0 0x00042044
/* TRP, DRP interrupt register offsets */
-#define DRP_INTERRUPT_STATUS 0x00040060
-#define TRP_INTERRUPT_0_STATUS 0x00024380
-#define DRP_INTERRUPT_CLEAR 0x00040058
-#define DRP_ECC_ERROR_CNTR_CLEAR 0x00040044
-#define TRP_INTERRUPT_0_CLEAR 0x00024384
-#define TRP_ECC_ERROR_CNTR_CLEAR 0x00023440
+#define DRP_INTERRUPT_STATUS 0x00041000
+#define TRP_INTERRUPT_0_STATUS 0x00020480
+#define DRP_INTERRUPT_CLEAR 0x00041008
+#define DRP_ECC_ERROR_CNTR_CLEAR 0x00040004
+#define TRP_INTERRUPT_0_CLEAR 0x00020484
+#define TRP_ECC_ERROR_CNTR_CLEAR 0x00020440
/* Mask and shift macros */
-#define ECC_DB_ERR_COUNT_MASK 0x0000003f
+#define ECC_DB_ERR_COUNT_MASK 0x0000001f
#define ECC_DB_ERR_WAYS_MASK 0xffff0000
#define ECC_DB_ERR_WAYS_SHIFT 16
@@ -90,7 +90,6 @@
};
struct erp_drvdata {
- struct edac_device_ctl_info *edev_ctl;
struct regmap *llcc_map;
};
@@ -107,9 +106,11 @@
switch (err_type) {
case LLCC_DRAM_CE:
case LLCC_DRAM_UE:
+ /* Clear the interrupt */
regmap_write(llcc_map, DRP_INTERRUPT_CLEAR, DRP_TRP_INT_CLEAR);
- regmap_write(llcc_map, TRP_INTERRUPT_CLEAR,
- DRP_ECC_ERROR_CNTR_CLEAR);
+ /* Clear the counters */
+ regmap_write(llcc_map, DRP_ECC_ERROR_CNTR_CLEAR,
+ DRP_TRP_CNT_CLEAR);
break;
case LLCC_TRAM_CE:
case LLCC_TRAM_UE:
@@ -190,7 +191,7 @@
for (i = 0; i < DRP_SYN_REG_CNT; i++) {
synd_reg = DRP_ECC_DB_ERR_SYN0 + (i * 4);
- regmap_read(llcc_map, synd_red, &synd_val);
+ regmap_read(llcc_map, synd_reg, &synd_val);
edac_printk(KERN_CRIT, EDAC_LLCC, "DRP_ECC_SYN%d: 0x%8x\n",
i, synd_val);
}
@@ -215,6 +216,7 @@
int sb_err_ways;
u32 synd_reg;
u32 synd_val;
+ u32 synd_reg_offset;
for (i = 0; i < DRP_SYN_REG_CNT; i++) {
synd_reg_offset = DRP_ECC_SB_ERR_SYN0 + (i * 4);
@@ -237,7 +239,8 @@
}
-static void dump_syn_reg(int err_type, struct regmap *llcc_map)
+static void dump_syn_reg(struct edac_device_ctl_info *edev_ctl,
+ int err_type, struct regmap *llcc_map)
{
switch (err_type) {
case LLCC_DRAM_CE:
@@ -256,7 +259,7 @@
qcom_llcc_clear_errors(err_type, llcc_map);
- errors[err_type].func(edev_ctl, 1, 0, errors[err_type].msg);
+ errors[err_type].func(edev_ctl, 0, 0, errors[err_type].msg);
}
static void qcom_llcc_poll_cache_errors
@@ -264,9 +267,7 @@
{
u32 drp_error;
u32 trp_error;
- struct erp_drvdata *drv;
-
- drv = container_of(edev_ctl, struct erp_drvdata, edev_ctl);
+ struct erp_drvdata *drv = edev_ctl->pvt_info;
/* Look for Data RAM errors */
regmap_read(drv->llcc_map, DRP_INTERRUPT_STATUS, &drp_error);
@@ -274,11 +275,11 @@
if (drp_error & SB_ECC_ERROR) {
edac_printk(KERN_CRIT, EDAC_LLCC,
"Single Bit Error detected in Data Ram\n");
- dump_syn_reg(LLCC_DRAM_CE, drv->llcc_map);
+ dump_syn_reg(edev_ctl, LLCC_DRAM_CE, drv->llcc_map);
} else if (drp_error & DB_ECC_ERROR) {
edac_printk(KERN_CRIT, EDAC_LLCC,
"Double Bit Error detected in Data Ram\n");
- dump_syn_reg(LLCC_DRAM_UE, drv->llcc_map);
+ dump_syn_reg(edev_ctl, LLCC_DRAM_UE, drv->llcc_map);
}
/* Look for Tag RAM errors */
@@ -286,11 +287,11 @@
if (trp_error & SB_ECC_ERROR) {
edac_printk(KERN_CRIT, EDAC_LLCC,
"Single Bit Error detected in Tag Ram\n");
- dump_syn_reg(LLCC_TRAM_CE, drv->llcc_map);
+ dump_syn_reg(edev_ctl, LLCC_TRAM_CE, drv->llcc_map);
} else if (trp_error & DB_ECC_ERROR) {
edac_printk(KERN_CRIT, EDAC_LLCC,
"Double Bit Error detected in Tag Ram\n");
- dump_syn_reg(LLCC_TRAM_UE, drv->llcc_map);
+ dump_syn_reg(edev_ctl, LLCC_TRAM_UE, drv->llcc_map);
}
}
@@ -298,11 +299,24 @@
{
int rc = 0;
struct erp_drvdata *drv;
+ struct edac_device_ctl_info *edev_ctl;
struct device *dev = &pdev->dev;
- drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
- if (!drv)
- return -ENOMEM;
+ /* Allocate edac control info */
+ edev_ctl = edac_device_alloc_ctl_info(sizeof(*drv), "qcom-llcc", 1,
+ NULL, 1, 1, NULL, 0, edac_device_alloc_index());
+
+ edev_ctl->dev = dev;
+ edev_ctl->mod_name = dev_name(dev);
+ edev_ctl->dev_name = dev_name(dev);
+ edev_ctl->ctl_name = "llcc";
+ edev_ctl->poll_msec = poll_msec;
+ edev_ctl->edac_check = qcom_llcc_poll_cache_errors;
+ edev_ctl->defer_work = 1;
+ edev_ctl->panic_on_ce = LLCC_ERP_PANIC_ON_CE;
+ edev_ctl->panic_on_ue = LLCC_ERP_PANIC_ON_UE;
+
+ drv = edev_ctl->pvt_info;
drv->llcc_map = syscon_node_to_regmap(dev->parent->of_node);
if (IS_ERR(drv->llcc_map)) {
@@ -310,32 +324,18 @@
return -ENOMEM;
}
- /* Allocate edac control info */
- drv->edev_ctl = edac_device_alloc_ctl_info(0, "qcom-llcc", 1, NULL, 1,
- 1, NULL, 0, edac_device_alloc_index());
+ platform_set_drvdata(pdev, edev_ctl);
- drv->edev_ctl->dev = dev;
- drv->edev_ctl->mod_name = dev_name(dev);
- drv->edev_ctl->dev_name = dev_name(dev);
- drv->edev_ctl->ctl_name = "llcc";
- drv->edev_ctl->poll_msec = poll_msec;
- drv->edev_ctl->edac_check = qcom_llcc_poll_cache_errors;
- drv->edev_ctl->defer_work = 1;
- drv->edev_ctl->panic_on_ce = LLCC_ERP_PANIC_ON_CE;
- drv->edev_ctl->panic_on_ue = LLCC_ERP_PANIC_ON_UE;
- platform_set_drvdata(pdev, drv);
-
- rc = edac_device_add_device(drv->edev_ctl);
+ rc = edac_device_add_device(edev_ctl);
if (rc)
- edac_device_free_ctl_info(drv->edev_ctl);
+ edac_device_free_ctl_info(edev_ctl);
return rc;
}
static int qcom_llcc_erp_remove(struct platform_device *pdev)
{
- struct erp_drvdata *drv = dev_get_drvdata(&pdev->dev);
- struct edac_device_ctl_info *edev_ctl = drv->edev_ctl;
+ struct edac_device_ctl_info *edev_ctl = dev_get_drvdata(&pdev->dev);
edac_device_del_device(edev_ctl->dev);
edac_device_free_ctl_info(edev_ctl);