Loading drivers/edac/Kconfig +1 −1 Original line number Diff line number Diff line Loading @@ -462,7 +462,7 @@ config EDAC_XGENE 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 Loading drivers/edac/qcom_llcc_edac.c +50 −50 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -90,7 +90,6 @@ struct errors_edac { }; struct erp_drvdata { struct edac_device_ctl_info *edev_ctl; struct regmap *llcc_map; }; Loading @@ -107,9 +106,11 @@ static void qcom_llcc_clear_errors(int err_type, struct regmap *llcc_map) 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: Loading Loading @@ -190,7 +191,7 @@ static void dump_drp_db_syn_reg(struct regmap *llcc_map) 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); } Loading @@ -215,6 +216,7 @@ static void dump_drp_sb_syn_reg(struct regmap *llcc_map) 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); Loading @@ -237,7 +239,8 @@ static void dump_drp_sb_syn_reg(struct regmap *llcc_map) } 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: Loading @@ -256,7 +259,7 @@ static void dump_syn_reg(int err_type, struct regmap *llcc_map) 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 Loading @@ -264,9 +267,7 @@ static void qcom_llcc_poll_cache_errors { 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); Loading @@ -274,11 +275,11 @@ static void qcom_llcc_poll_cache_errors 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 */ Loading @@ -286,11 +287,11 @@ static void qcom_llcc_poll_cache_errors 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); } } Loading @@ -298,11 +299,24 @@ static int qcom_llcc_erp_probe(struct platform_device *pdev) { 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)) { Loading @@ -310,32 +324,18 @@ static int qcom_llcc_erp_probe(struct platform_device *pdev) 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()); 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); platform_set_drvdata(pdev, 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); Loading Loading
drivers/edac/Kconfig +1 −1 Original line number Diff line number Diff line Loading @@ -462,7 +462,7 @@ config EDAC_XGENE 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 Loading
drivers/edac/qcom_llcc_edac.c +50 −50 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -90,7 +90,6 @@ struct errors_edac { }; struct erp_drvdata { struct edac_device_ctl_info *edev_ctl; struct regmap *llcc_map; }; Loading @@ -107,9 +106,11 @@ static void qcom_llcc_clear_errors(int err_type, struct regmap *llcc_map) 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: Loading Loading @@ -190,7 +191,7 @@ static void dump_drp_db_syn_reg(struct regmap *llcc_map) 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); } Loading @@ -215,6 +216,7 @@ static void dump_drp_sb_syn_reg(struct regmap *llcc_map) 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); Loading @@ -237,7 +239,8 @@ static void dump_drp_sb_syn_reg(struct regmap *llcc_map) } 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: Loading @@ -256,7 +259,7 @@ static void dump_syn_reg(int err_type, struct regmap *llcc_map) 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 Loading @@ -264,9 +267,7 @@ static void qcom_llcc_poll_cache_errors { 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); Loading @@ -274,11 +275,11 @@ static void qcom_llcc_poll_cache_errors 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 */ Loading @@ -286,11 +287,11 @@ static void qcom_llcc_poll_cache_errors 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); } } Loading @@ -298,11 +299,24 @@ static int qcom_llcc_erp_probe(struct platform_device *pdev) { 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)) { Loading @@ -310,32 +324,18 @@ static int qcom_llcc_erp_probe(struct platform_device *pdev) 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()); 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); platform_set_drvdata(pdev, 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); Loading