Loading drivers/edac/qcom_llcc_edac.c +120 −51 Original line number Diff line number Diff line Loading @@ -39,6 +39,10 @@ #define DRP_SYN_REG_CNT 8 #define LLCC_COMMON_STATUS0 0x0003000C #define LLCC_LB_CNT_MASK 0xf0000000 #define LLCC_LB_CNT_SHIFT 28 /* single & Double Bit syndrome register offsets */ #define TRP_ECC_SB_ERR_SYN0 0x0002304C #define TRP_ECC_DB_ERR_SYN0 0x00020370 Loading Loading @@ -97,7 +101,10 @@ struct errors_edac { struct erp_drvdata { struct regmap *llcc_map; phys_addr_t *llcc_banks; u32 ecc_irq; u32 num_banks; u32 b_off; }; static const struct errors_edac errors[] = { Loading @@ -108,29 +115,32 @@ static const struct errors_edac errors[] = { }; /* Clear the error interrupt and counter registers */ static void qcom_llcc_clear_errors(int err_type, struct regmap *llcc_map) static void qcom_llcc_clear_errors(int err_type, struct erp_drvdata *drv) { 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(drv->llcc_map, drv->b_off + DRP_INTERRUPT_CLEAR, DRP_TRP_INT_CLEAR); /* Clear the counters */ regmap_write(llcc_map, DRP_ECC_ERROR_CNTR_CLEAR, regmap_write(drv->llcc_map, drv->b_off + DRP_ECC_ERROR_CNTR_CLEAR, DRP_TRP_CNT_CLEAR); break; case LLCC_TRAM_CE: case LLCC_TRAM_UE: regmap_write(llcc_map, TRP_INTERRUPT_0_CLEAR, regmap_write(drv->llcc_map, drv->b_off + TRP_INTERRUPT_0_CLEAR, DRP_TRP_INT_CLEAR); regmap_write(llcc_map, TRP_ECC_ERROR_CNTR_CLEAR, regmap_write(drv->llcc_map, drv->b_off + TRP_ECC_ERROR_CNTR_CLEAR, DRP_TRP_CNT_CLEAR); break; } } /* Dump syndrome registers for tag Ram Double bit errors */ static void dump_trp_db_syn_reg(struct regmap *llcc_map) static void dump_trp_db_syn_reg(struct erp_drvdata *drv, u32 bank) { int i; int db_err_cnt; Loading @@ -140,17 +150,20 @@ static void dump_trp_db_syn_reg(struct regmap *llcc_map) for (i = 0; i < TRP_SYN_REG_CNT; i++) { synd_reg = TRP_ECC_DB_ERR_SYN0 + (i * 4); regmap_read(llcc_map, synd_reg, &synd_val); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + synd_reg, &synd_val); edac_printk(KERN_CRIT, EDAC_LLCC, "TRP_ECC_SYN%d: 0x%8x\n", i, synd_val); } regmap_read(llcc_map, TRP_ECC_ERROR_STATUS1, &db_err_cnt); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + TRP_ECC_ERROR_STATUS1, &db_err_cnt); db_err_cnt = (db_err_cnt & ECC_DB_ERR_COUNT_MASK); edac_printk(KERN_CRIT, EDAC_LLCC, "Double-Bit error count: 0x%4x\n", db_err_cnt); regmap_read(llcc_map, TRP_ECC_ERROR_STATUS0, &db_err_ways); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + TRP_ECC_ERROR_STATUS0, &db_err_ways); db_err_ways = (db_err_ways & ECC_DB_ERR_WAYS_MASK); db_err_ways >>= ECC_DB_ERR_WAYS_SHIFT; Loading @@ -159,7 +172,7 @@ static void dump_trp_db_syn_reg(struct regmap *llcc_map) } /* Dump syndrome register for tag Ram Single Bit Errors */ static void dump_trp_sb_syn_reg(struct regmap *llcc_map) static void dump_trp_sb_syn_reg(struct erp_drvdata *drv, u32 bank) { int i; int sb_err_cnt; Loading @@ -169,18 +182,21 @@ static void dump_trp_sb_syn_reg(struct regmap *llcc_map) for (i = 0; i < TRP_SYN_REG_CNT; i++) { synd_reg = TRP_ECC_SB_ERR_SYN0 + (i * 4); regmap_read(llcc_map, synd_reg, &synd_val); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + synd_reg, &synd_val); edac_printk(KERN_CRIT, EDAC_LLCC, "TRP_ECC_SYN%d: 0x%8x\n", i, synd_val); } regmap_read(llcc_map, TRP_ECC_ERROR_STATUS1, &sb_err_cnt); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + TRP_ECC_ERROR_STATUS1, &sb_err_cnt); sb_err_cnt = (sb_err_cnt & ECC_SB_ERR_COUNT_MASK); sb_err_cnt >>= ECC_SB_ERR_COUNT_SHIFT; edac_printk(KERN_CRIT, EDAC_LLCC, "Single-Bit error count: 0x%4x\n", sb_err_cnt); regmap_read(llcc_map, TRP_ECC_ERROR_STATUS0, &sb_err_ways); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + TRP_ECC_ERROR_STATUS0, &sb_err_ways); sb_err_ways = sb_err_ways & ECC_SB_ERR_WAYS_MASK; edac_printk(KERN_CRIT, EDAC_LLCC, "Single-Bit error ways: 0x%4x\n", Loading @@ -188,7 +204,7 @@ static void dump_trp_sb_syn_reg(struct regmap *llcc_map) } /* Dump syndrome registers for Data Ram Double bit errors */ static void dump_drp_db_syn_reg(struct regmap *llcc_map) static void dump_drp_db_syn_reg(struct erp_drvdata *drv, u32 bank) { int i; int db_err_cnt; Loading @@ -198,17 +214,20 @@ 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_reg, &synd_val); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + synd_reg, &synd_val); edac_printk(KERN_CRIT, EDAC_LLCC, "DRP_ECC_SYN%d: 0x%8x\n", i, synd_val); } regmap_read(llcc_map, DRP_ECC_ERROR_STATUS1, &db_err_cnt); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + DRP_ECC_ERROR_STATUS1, &db_err_cnt); db_err_cnt = (db_err_cnt & ECC_DB_ERR_COUNT_MASK); edac_printk(KERN_CRIT, EDAC_LLCC, "Double-Bit error count: 0x%4x\n", db_err_cnt); regmap_read(llcc_map, DRP_ECC_ERROR_STATUS0, &db_err_ways); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + DRP_ECC_ERROR_STATUS0, &db_err_ways); db_err_ways &= ECC_DB_ERR_WAYS_MASK; db_err_ways >>= ECC_DB_ERR_WAYS_SHIFT; edac_printk(KERN_CRIT, EDAC_LLCC, "Double-Bit error ways: 0x%4x\n", Loading @@ -216,7 +235,7 @@ static void dump_drp_db_syn_reg(struct regmap *llcc_map) } /* Dump Syndrome registers for Data Ram Single bit errors*/ static void dump_drp_sb_syn_reg(struct regmap *llcc_map) static void dump_drp_sb_syn_reg(struct erp_drvdata *drv, u32 bank) { int i; int sb_err_cnt; Loading @@ -226,18 +245,21 @@ static void dump_drp_sb_syn_reg(struct regmap *llcc_map) for (i = 0; i < DRP_SYN_REG_CNT; i++) { synd_reg = DRP_ECC_SB_ERR_SYN0 + (i * 4); regmap_read(llcc_map, synd_reg, &synd_val); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + synd_reg, &synd_val); edac_printk(KERN_CRIT, EDAC_LLCC, "DRP_ECC_SYN%d: 0x%8x\n", i, synd_val); } regmap_read(llcc_map, DRP_ECC_ERROR_STATUS1, &sb_err_cnt); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + DRP_ECC_ERROR_STATUS1, &sb_err_cnt); sb_err_cnt &= ECC_SB_ERR_COUNT_MASK; sb_err_cnt >>= ECC_SB_ERR_COUNT_SHIFT; edac_printk(KERN_CRIT, EDAC_LLCC, "Single-Bit error count: 0x%4x\n", sb_err_cnt); regmap_read(llcc_map, DRP_ECC_ERROR_STATUS0, &sb_err_ways); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + DRP_ECC_ERROR_STATUS0, &sb_err_ways); sb_err_ways = sb_err_ways & ECC_SB_ERR_WAYS_MASK; edac_printk(KERN_CRIT, EDAC_LLCC, "Single-Bit error ways: 0x%4x\n", Loading @@ -246,24 +268,26 @@ static void dump_drp_sb_syn_reg(struct regmap *llcc_map) static void dump_syn_reg(struct edac_device_ctl_info *edev_ctl, int err_type, struct regmap *llcc_map) int err_type, u32 bank) { struct erp_drvdata *drv = edev_ctl->pvt_info; switch (err_type) { case LLCC_DRAM_CE: dump_drp_sb_syn_reg(llcc_map); dump_drp_sb_syn_reg(drv, bank); break; case LLCC_DRAM_UE: dump_drp_db_syn_reg(llcc_map); dump_drp_db_syn_reg(drv, bank); break; case LLCC_TRAM_CE: dump_trp_sb_syn_reg(llcc_map); dump_trp_sb_syn_reg(drv, bank); break; case LLCC_TRAM_UE: dump_trp_db_syn_reg(llcc_map); dump_trp_db_syn_reg(drv, bank); break; } qcom_llcc_clear_errors(err_type, llcc_map); qcom_llcc_clear_errors(err_type, drv); errors[err_type].func(edev_ctl, 0, 0, errors[err_type].msg); } Loading @@ -274,30 +298,36 @@ static void qcom_llcc_check_cache_errors u32 drp_error; u32 trp_error; struct erp_drvdata *drv = edev_ctl->pvt_info; u32 i; for (i = 0; i < drv->num_banks; i++) { /* Look for Data RAM errors */ regmap_read(drv->llcc_map, DRP_INTERRUPT_STATUS, &drp_error); regmap_read(drv->llcc_map, drv->llcc_banks[i] + DRP_INTERRUPT_STATUS, &drp_error); if (drp_error & SB_ECC_ERROR) { edac_printk(KERN_CRIT, EDAC_LLCC, "Single Bit Error detected in Data Ram\n"); dump_syn_reg(edev_ctl, LLCC_DRAM_CE, drv->llcc_map); dump_syn_reg(edev_ctl, LLCC_DRAM_CE, i); } else if (drp_error & DB_ECC_ERROR) { edac_printk(KERN_CRIT, EDAC_LLCC, "Double Bit Error detected in Data Ram\n"); dump_syn_reg(edev_ctl, LLCC_DRAM_UE, drv->llcc_map); dump_syn_reg(edev_ctl, LLCC_DRAM_UE, i); } /* Look for Tag RAM errors */ regmap_read(drv->llcc_map, TRP_INTERRUPT_0_STATUS, &trp_error); regmap_read(drv->llcc_map, drv->llcc_banks[i] + TRP_INTERRUPT_0_STATUS, &trp_error); if (trp_error & SB_ECC_ERROR) { edac_printk(KERN_CRIT, EDAC_LLCC, "Single Bit Error detected in Tag Ram\n"); dump_syn_reg(edev_ctl, LLCC_TRAM_CE, drv->llcc_map); dump_syn_reg(edev_ctl, LLCC_TRAM_CE, i); } else if (trp_error & DB_ECC_ERROR) { edac_printk(KERN_CRIT, EDAC_LLCC, "Double Bit Error detected in Tag Ram\n"); dump_syn_reg(edev_ctl, LLCC_TRAM_UE, drv->llcc_map); dump_syn_reg(edev_ctl, LLCC_TRAM_UE, i); } } } Loading @@ -319,6 +349,8 @@ static int qcom_llcc_erp_probe(struct platform_device *pdev) struct erp_drvdata *drv; struct edac_device_ctl_info *edev_ctl; struct device *dev = &pdev->dev; u32 *banks; u32 i; /* Allocate edac control info */ edev_ctl = edac_device_alloc_ctl_info(sizeof(*drv), "qcom-llcc", 1, Loading Loading @@ -358,6 +390,43 @@ static int qcom_llcc_erp_probe(struct platform_device *pdev) } } /* Find the number of LLC banks supported */ regmap_read(drv->llcc_map, LLCC_COMMON_STATUS0, &drv->num_banks); drv->num_banks &= LLCC_LB_CNT_MASK; drv->num_banks >>= LLCC_LB_CNT_SHIFT; drv->llcc_banks = devm_kzalloc(&pdev->dev, sizeof(phys_addr_t) * drv->num_banks, GFP_KERNEL); if (!drv->num_banks) { dev_err(dev, "Cannot allocate memory for llcc_banks\n"); return -ENOMEM; } banks = devm_kzalloc(&pdev->dev, sizeof(u32) * drv->num_banks, GFP_KERNEL); if (!banks) return -ENOMEM; rc = of_property_read_u32_array(dev->parent->of_node, "qcom,llcc-banks-off", banks, drv->num_banks); if (rc) { dev_err(dev, "Cannot read llcc-banks-off property\n"); return -EINVAL; } rc = of_property_read_u32(dev->parent->of_node, "qcom,llcc-broadcast-off", &drv->b_off); if (rc) { dev_err(dev, "Cannot read llcc-broadcast-off property\n"); return -EINVAL; } for (i = 0; i < drv->num_banks; i++) drv->llcc_banks[i] = banks[i]; platform_set_drvdata(pdev, edev_ctl); rc = edac_device_add_device(edev_ctl); Loading drivers/soc/qcom/llcc-core.c +16 −12 Original line number Diff line number Diff line Loading @@ -33,42 +33,39 @@ #define SB_DB_TRP_INTERRUPT_ENABLE 0x3 #define TRP0_INTERRUPT_ENABLE 0x1 #define DRP0_INTERRUPT_ENABLE BIT(6) #define COMMON_INTERRUPT_0_AMON BIT(8) #define SB_DB_DRP_INTERRUPT_ENABLE 0x3 static void qcom_llcc_core_setup(struct regmap *llcc_regmap) static void qcom_llcc_core_setup(struct regmap *llcc_regmap, uint32_t b_off) { u32 sb_err_threshold; /* Enable TRP in instance 2 of common interrupt enable register */ regmap_update_bits(llcc_regmap, CMN_INTERRUPT_2_ENABLE, regmap_update_bits(llcc_regmap, b_off + CMN_INTERRUPT_2_ENABLE, TRP0_INTERRUPT_ENABLE, TRP0_INTERRUPT_ENABLE); /* Enable ECC interrupts on Tag Ram */ regmap_update_bits(llcc_regmap, TRP_INTERRUPT_0_ENABLE, regmap_update_bits(llcc_regmap, b_off + TRP_INTERRUPT_0_ENABLE, SB_DB_TRP_INTERRUPT_ENABLE, SB_DB_TRP_INTERRUPT_ENABLE); /* Enable SB error for Data RAM */ sb_err_threshold = (SB_ERROR_THRESHOLD << SB_ERROR_THRESHOLD_SHIFT); regmap_write(llcc_regmap, DRP_ECC_ERROR_CFG, sb_err_threshold); regmap_write(llcc_regmap, b_off + DRP_ECC_ERROR_CFG, sb_err_threshold); /* Enable DRP in instance 2 of common interrupt enable register */ regmap_update_bits(llcc_regmap, CMN_INTERRUPT_2_ENABLE, regmap_update_bits(llcc_regmap, b_off + CMN_INTERRUPT_2_ENABLE, DRP0_INTERRUPT_ENABLE, DRP0_INTERRUPT_ENABLE); /* Enable ECC interrupts on Data Ram */ regmap_write(llcc_regmap, DRP_INTERRUPT_ENABLE, regmap_write(llcc_regmap, b_off + DRP_INTERRUPT_ENABLE, SB_DB_DRP_INTERRUPT_ENABLE); /* Enable AMON interrupt in the common interrupt register */ regmap_update_bits(llcc_regmap, CMN_INTERRUPT_0_ENABLE, COMMON_INTERRUPT_0_AMON, COMMON_INTERRUPT_0_AMON); } static int qcom_llcc_core_probe(struct platform_device *pdev) { struct regmap *llcc_regmap; struct device *dev = &pdev->dev; u32 b_off = 0; int ret = 0; llcc_regmap = syscon_node_to_regmap(dev->of_node); Loading @@ -77,7 +74,14 @@ static int qcom_llcc_core_probe(struct platform_device *pdev) return PTR_ERR(llcc_regmap); } qcom_llcc_core_setup(llcc_regmap); ret = of_property_read_u32(dev->of_node, "qcom,llcc-broadcast-off", &b_off); if (ret) { dev_err(&pdev->dev, "Unable to read broadcast-off\n"); return -EINVAL; } qcom_llcc_core_setup(llcc_regmap, b_off); return 0; } Loading drivers/soc/qcom/llcc-slice.c +16 −5 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ #define CACHE_LINE_SIZE_SHIFT 6 #define SIZE_PER_LLCC_SHIFT 2 #define MAX_CAP_TO_BYTES(n) (n * 1024) #define LLCC_TRP_ACT_CTRLn(n) (n * 0x1000) #define LLCC_TRP_STATUSn(n) (4 + n * 0x1000) Loading @@ -63,6 +64,7 @@ struct llcc_drv_data { struct mutex slice_mutex; u32 llcc_config_data_sz; u32 max_slices; u32 b_off; unsigned long *llcc_slice_map; }; Loading Loading @@ -172,8 +174,8 @@ static int llcc_update_act_ctrl(struct llcc_drv_data *drv, u32 sid, u32 slice_status; unsigned long timeout; act_ctrl_reg = LLCC_TRP_ACT_CTRLn(sid); status_reg = LLCC_TRP_STATUSn(sid); act_ctrl_reg = drv->b_off + LLCC_TRP_ACT_CTRLn(sid); status_reg = drv->b_off + LLCC_TRP_STATUSn(sid); regmap_write(drv->llcc_map, act_ctrl_reg, act_ctrl_reg_val); Loading Loading @@ -323,13 +325,14 @@ static void qcom_llcc_cfg_program(struct platform_device *pdev) const struct llcc_slice_config *llcc_table; struct llcc_drv_data *drv = platform_get_drvdata(pdev); struct llcc_slice_desc desc; u32 b_off = drv->b_off; sz = drv->llcc_config_data_sz; llcc_table = drv->slice_data; for (i = 0; i < sz; i++) { attr1_cfg = LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id); attr0_cfg = LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id); attr1_cfg = b_off + LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id); attr0_cfg = b_off + LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id); attr1_val = llcc_table[i].cache_mode; attr1_val |= (llcc_table[i].probe_target_ways << Loading Loading @@ -386,7 +389,15 @@ int qcom_llcc_probe(struct platform_device *pdev, rc = of_property_read_u32(pdev->dev.of_node, "max-slices", &drv_data->max_slices); if (rc) { dev_info(&pdev->dev, "Invalid max-slices dt entry\n"); dev_err(&pdev->dev, "Invalid max-slices dt entry\n"); devm_kfree(&pdev->dev, drv_data); return rc; } rc = of_property_read_u32(pdev->dev.parent->of_node, "qcom,llcc-broadcast-off", &drv_data->b_off); if (rc) { dev_err(&pdev->dev, "Invalid qcom,broadcast-off entry\n"); devm_kfree(&pdev->dev, drv_data); return rc; } Loading Loading
drivers/edac/qcom_llcc_edac.c +120 −51 Original line number Diff line number Diff line Loading @@ -39,6 +39,10 @@ #define DRP_SYN_REG_CNT 8 #define LLCC_COMMON_STATUS0 0x0003000C #define LLCC_LB_CNT_MASK 0xf0000000 #define LLCC_LB_CNT_SHIFT 28 /* single & Double Bit syndrome register offsets */ #define TRP_ECC_SB_ERR_SYN0 0x0002304C #define TRP_ECC_DB_ERR_SYN0 0x00020370 Loading Loading @@ -97,7 +101,10 @@ struct errors_edac { struct erp_drvdata { struct regmap *llcc_map; phys_addr_t *llcc_banks; u32 ecc_irq; u32 num_banks; u32 b_off; }; static const struct errors_edac errors[] = { Loading @@ -108,29 +115,32 @@ static const struct errors_edac errors[] = { }; /* Clear the error interrupt and counter registers */ static void qcom_llcc_clear_errors(int err_type, struct regmap *llcc_map) static void qcom_llcc_clear_errors(int err_type, struct erp_drvdata *drv) { 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(drv->llcc_map, drv->b_off + DRP_INTERRUPT_CLEAR, DRP_TRP_INT_CLEAR); /* Clear the counters */ regmap_write(llcc_map, DRP_ECC_ERROR_CNTR_CLEAR, regmap_write(drv->llcc_map, drv->b_off + DRP_ECC_ERROR_CNTR_CLEAR, DRP_TRP_CNT_CLEAR); break; case LLCC_TRAM_CE: case LLCC_TRAM_UE: regmap_write(llcc_map, TRP_INTERRUPT_0_CLEAR, regmap_write(drv->llcc_map, drv->b_off + TRP_INTERRUPT_0_CLEAR, DRP_TRP_INT_CLEAR); regmap_write(llcc_map, TRP_ECC_ERROR_CNTR_CLEAR, regmap_write(drv->llcc_map, drv->b_off + TRP_ECC_ERROR_CNTR_CLEAR, DRP_TRP_CNT_CLEAR); break; } } /* Dump syndrome registers for tag Ram Double bit errors */ static void dump_trp_db_syn_reg(struct regmap *llcc_map) static void dump_trp_db_syn_reg(struct erp_drvdata *drv, u32 bank) { int i; int db_err_cnt; Loading @@ -140,17 +150,20 @@ static void dump_trp_db_syn_reg(struct regmap *llcc_map) for (i = 0; i < TRP_SYN_REG_CNT; i++) { synd_reg = TRP_ECC_DB_ERR_SYN0 + (i * 4); regmap_read(llcc_map, synd_reg, &synd_val); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + synd_reg, &synd_val); edac_printk(KERN_CRIT, EDAC_LLCC, "TRP_ECC_SYN%d: 0x%8x\n", i, synd_val); } regmap_read(llcc_map, TRP_ECC_ERROR_STATUS1, &db_err_cnt); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + TRP_ECC_ERROR_STATUS1, &db_err_cnt); db_err_cnt = (db_err_cnt & ECC_DB_ERR_COUNT_MASK); edac_printk(KERN_CRIT, EDAC_LLCC, "Double-Bit error count: 0x%4x\n", db_err_cnt); regmap_read(llcc_map, TRP_ECC_ERROR_STATUS0, &db_err_ways); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + TRP_ECC_ERROR_STATUS0, &db_err_ways); db_err_ways = (db_err_ways & ECC_DB_ERR_WAYS_MASK); db_err_ways >>= ECC_DB_ERR_WAYS_SHIFT; Loading @@ -159,7 +172,7 @@ static void dump_trp_db_syn_reg(struct regmap *llcc_map) } /* Dump syndrome register for tag Ram Single Bit Errors */ static void dump_trp_sb_syn_reg(struct regmap *llcc_map) static void dump_trp_sb_syn_reg(struct erp_drvdata *drv, u32 bank) { int i; int sb_err_cnt; Loading @@ -169,18 +182,21 @@ static void dump_trp_sb_syn_reg(struct regmap *llcc_map) for (i = 0; i < TRP_SYN_REG_CNT; i++) { synd_reg = TRP_ECC_SB_ERR_SYN0 + (i * 4); regmap_read(llcc_map, synd_reg, &synd_val); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + synd_reg, &synd_val); edac_printk(KERN_CRIT, EDAC_LLCC, "TRP_ECC_SYN%d: 0x%8x\n", i, synd_val); } regmap_read(llcc_map, TRP_ECC_ERROR_STATUS1, &sb_err_cnt); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + TRP_ECC_ERROR_STATUS1, &sb_err_cnt); sb_err_cnt = (sb_err_cnt & ECC_SB_ERR_COUNT_MASK); sb_err_cnt >>= ECC_SB_ERR_COUNT_SHIFT; edac_printk(KERN_CRIT, EDAC_LLCC, "Single-Bit error count: 0x%4x\n", sb_err_cnt); regmap_read(llcc_map, TRP_ECC_ERROR_STATUS0, &sb_err_ways); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + TRP_ECC_ERROR_STATUS0, &sb_err_ways); sb_err_ways = sb_err_ways & ECC_SB_ERR_WAYS_MASK; edac_printk(KERN_CRIT, EDAC_LLCC, "Single-Bit error ways: 0x%4x\n", Loading @@ -188,7 +204,7 @@ static void dump_trp_sb_syn_reg(struct regmap *llcc_map) } /* Dump syndrome registers for Data Ram Double bit errors */ static void dump_drp_db_syn_reg(struct regmap *llcc_map) static void dump_drp_db_syn_reg(struct erp_drvdata *drv, u32 bank) { int i; int db_err_cnt; Loading @@ -198,17 +214,20 @@ 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_reg, &synd_val); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + synd_reg, &synd_val); edac_printk(KERN_CRIT, EDAC_LLCC, "DRP_ECC_SYN%d: 0x%8x\n", i, synd_val); } regmap_read(llcc_map, DRP_ECC_ERROR_STATUS1, &db_err_cnt); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + DRP_ECC_ERROR_STATUS1, &db_err_cnt); db_err_cnt = (db_err_cnt & ECC_DB_ERR_COUNT_MASK); edac_printk(KERN_CRIT, EDAC_LLCC, "Double-Bit error count: 0x%4x\n", db_err_cnt); regmap_read(llcc_map, DRP_ECC_ERROR_STATUS0, &db_err_ways); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + DRP_ECC_ERROR_STATUS0, &db_err_ways); db_err_ways &= ECC_DB_ERR_WAYS_MASK; db_err_ways >>= ECC_DB_ERR_WAYS_SHIFT; edac_printk(KERN_CRIT, EDAC_LLCC, "Double-Bit error ways: 0x%4x\n", Loading @@ -216,7 +235,7 @@ static void dump_drp_db_syn_reg(struct regmap *llcc_map) } /* Dump Syndrome registers for Data Ram Single bit errors*/ static void dump_drp_sb_syn_reg(struct regmap *llcc_map) static void dump_drp_sb_syn_reg(struct erp_drvdata *drv, u32 bank) { int i; int sb_err_cnt; Loading @@ -226,18 +245,21 @@ static void dump_drp_sb_syn_reg(struct regmap *llcc_map) for (i = 0; i < DRP_SYN_REG_CNT; i++) { synd_reg = DRP_ECC_SB_ERR_SYN0 + (i * 4); regmap_read(llcc_map, synd_reg, &synd_val); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + synd_reg, &synd_val); edac_printk(KERN_CRIT, EDAC_LLCC, "DRP_ECC_SYN%d: 0x%8x\n", i, synd_val); } regmap_read(llcc_map, DRP_ECC_ERROR_STATUS1, &sb_err_cnt); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + DRP_ECC_ERROR_STATUS1, &sb_err_cnt); sb_err_cnt &= ECC_SB_ERR_COUNT_MASK; sb_err_cnt >>= ECC_SB_ERR_COUNT_SHIFT; edac_printk(KERN_CRIT, EDAC_LLCC, "Single-Bit error count: 0x%4x\n", sb_err_cnt); regmap_read(llcc_map, DRP_ECC_ERROR_STATUS0, &sb_err_ways); regmap_read(drv->llcc_map, drv->llcc_banks[bank] + DRP_ECC_ERROR_STATUS0, &sb_err_ways); sb_err_ways = sb_err_ways & ECC_SB_ERR_WAYS_MASK; edac_printk(KERN_CRIT, EDAC_LLCC, "Single-Bit error ways: 0x%4x\n", Loading @@ -246,24 +268,26 @@ static void dump_drp_sb_syn_reg(struct regmap *llcc_map) static void dump_syn_reg(struct edac_device_ctl_info *edev_ctl, int err_type, struct regmap *llcc_map) int err_type, u32 bank) { struct erp_drvdata *drv = edev_ctl->pvt_info; switch (err_type) { case LLCC_DRAM_CE: dump_drp_sb_syn_reg(llcc_map); dump_drp_sb_syn_reg(drv, bank); break; case LLCC_DRAM_UE: dump_drp_db_syn_reg(llcc_map); dump_drp_db_syn_reg(drv, bank); break; case LLCC_TRAM_CE: dump_trp_sb_syn_reg(llcc_map); dump_trp_sb_syn_reg(drv, bank); break; case LLCC_TRAM_UE: dump_trp_db_syn_reg(llcc_map); dump_trp_db_syn_reg(drv, bank); break; } qcom_llcc_clear_errors(err_type, llcc_map); qcom_llcc_clear_errors(err_type, drv); errors[err_type].func(edev_ctl, 0, 0, errors[err_type].msg); } Loading @@ -274,30 +298,36 @@ static void qcom_llcc_check_cache_errors u32 drp_error; u32 trp_error; struct erp_drvdata *drv = edev_ctl->pvt_info; u32 i; for (i = 0; i < drv->num_banks; i++) { /* Look for Data RAM errors */ regmap_read(drv->llcc_map, DRP_INTERRUPT_STATUS, &drp_error); regmap_read(drv->llcc_map, drv->llcc_banks[i] + DRP_INTERRUPT_STATUS, &drp_error); if (drp_error & SB_ECC_ERROR) { edac_printk(KERN_CRIT, EDAC_LLCC, "Single Bit Error detected in Data Ram\n"); dump_syn_reg(edev_ctl, LLCC_DRAM_CE, drv->llcc_map); dump_syn_reg(edev_ctl, LLCC_DRAM_CE, i); } else if (drp_error & DB_ECC_ERROR) { edac_printk(KERN_CRIT, EDAC_LLCC, "Double Bit Error detected in Data Ram\n"); dump_syn_reg(edev_ctl, LLCC_DRAM_UE, drv->llcc_map); dump_syn_reg(edev_ctl, LLCC_DRAM_UE, i); } /* Look for Tag RAM errors */ regmap_read(drv->llcc_map, TRP_INTERRUPT_0_STATUS, &trp_error); regmap_read(drv->llcc_map, drv->llcc_banks[i] + TRP_INTERRUPT_0_STATUS, &trp_error); if (trp_error & SB_ECC_ERROR) { edac_printk(KERN_CRIT, EDAC_LLCC, "Single Bit Error detected in Tag Ram\n"); dump_syn_reg(edev_ctl, LLCC_TRAM_CE, drv->llcc_map); dump_syn_reg(edev_ctl, LLCC_TRAM_CE, i); } else if (trp_error & DB_ECC_ERROR) { edac_printk(KERN_CRIT, EDAC_LLCC, "Double Bit Error detected in Tag Ram\n"); dump_syn_reg(edev_ctl, LLCC_TRAM_UE, drv->llcc_map); dump_syn_reg(edev_ctl, LLCC_TRAM_UE, i); } } } Loading @@ -319,6 +349,8 @@ static int qcom_llcc_erp_probe(struct platform_device *pdev) struct erp_drvdata *drv; struct edac_device_ctl_info *edev_ctl; struct device *dev = &pdev->dev; u32 *banks; u32 i; /* Allocate edac control info */ edev_ctl = edac_device_alloc_ctl_info(sizeof(*drv), "qcom-llcc", 1, Loading Loading @@ -358,6 +390,43 @@ static int qcom_llcc_erp_probe(struct platform_device *pdev) } } /* Find the number of LLC banks supported */ regmap_read(drv->llcc_map, LLCC_COMMON_STATUS0, &drv->num_banks); drv->num_banks &= LLCC_LB_CNT_MASK; drv->num_banks >>= LLCC_LB_CNT_SHIFT; drv->llcc_banks = devm_kzalloc(&pdev->dev, sizeof(phys_addr_t) * drv->num_banks, GFP_KERNEL); if (!drv->num_banks) { dev_err(dev, "Cannot allocate memory for llcc_banks\n"); return -ENOMEM; } banks = devm_kzalloc(&pdev->dev, sizeof(u32) * drv->num_banks, GFP_KERNEL); if (!banks) return -ENOMEM; rc = of_property_read_u32_array(dev->parent->of_node, "qcom,llcc-banks-off", banks, drv->num_banks); if (rc) { dev_err(dev, "Cannot read llcc-banks-off property\n"); return -EINVAL; } rc = of_property_read_u32(dev->parent->of_node, "qcom,llcc-broadcast-off", &drv->b_off); if (rc) { dev_err(dev, "Cannot read llcc-broadcast-off property\n"); return -EINVAL; } for (i = 0; i < drv->num_banks; i++) drv->llcc_banks[i] = banks[i]; platform_set_drvdata(pdev, edev_ctl); rc = edac_device_add_device(edev_ctl); Loading
drivers/soc/qcom/llcc-core.c +16 −12 Original line number Diff line number Diff line Loading @@ -33,42 +33,39 @@ #define SB_DB_TRP_INTERRUPT_ENABLE 0x3 #define TRP0_INTERRUPT_ENABLE 0x1 #define DRP0_INTERRUPT_ENABLE BIT(6) #define COMMON_INTERRUPT_0_AMON BIT(8) #define SB_DB_DRP_INTERRUPT_ENABLE 0x3 static void qcom_llcc_core_setup(struct regmap *llcc_regmap) static void qcom_llcc_core_setup(struct regmap *llcc_regmap, uint32_t b_off) { u32 sb_err_threshold; /* Enable TRP in instance 2 of common interrupt enable register */ regmap_update_bits(llcc_regmap, CMN_INTERRUPT_2_ENABLE, regmap_update_bits(llcc_regmap, b_off + CMN_INTERRUPT_2_ENABLE, TRP0_INTERRUPT_ENABLE, TRP0_INTERRUPT_ENABLE); /* Enable ECC interrupts on Tag Ram */ regmap_update_bits(llcc_regmap, TRP_INTERRUPT_0_ENABLE, regmap_update_bits(llcc_regmap, b_off + TRP_INTERRUPT_0_ENABLE, SB_DB_TRP_INTERRUPT_ENABLE, SB_DB_TRP_INTERRUPT_ENABLE); /* Enable SB error for Data RAM */ sb_err_threshold = (SB_ERROR_THRESHOLD << SB_ERROR_THRESHOLD_SHIFT); regmap_write(llcc_regmap, DRP_ECC_ERROR_CFG, sb_err_threshold); regmap_write(llcc_regmap, b_off + DRP_ECC_ERROR_CFG, sb_err_threshold); /* Enable DRP in instance 2 of common interrupt enable register */ regmap_update_bits(llcc_regmap, CMN_INTERRUPT_2_ENABLE, regmap_update_bits(llcc_regmap, b_off + CMN_INTERRUPT_2_ENABLE, DRP0_INTERRUPT_ENABLE, DRP0_INTERRUPT_ENABLE); /* Enable ECC interrupts on Data Ram */ regmap_write(llcc_regmap, DRP_INTERRUPT_ENABLE, regmap_write(llcc_regmap, b_off + DRP_INTERRUPT_ENABLE, SB_DB_DRP_INTERRUPT_ENABLE); /* Enable AMON interrupt in the common interrupt register */ regmap_update_bits(llcc_regmap, CMN_INTERRUPT_0_ENABLE, COMMON_INTERRUPT_0_AMON, COMMON_INTERRUPT_0_AMON); } static int qcom_llcc_core_probe(struct platform_device *pdev) { struct regmap *llcc_regmap; struct device *dev = &pdev->dev; u32 b_off = 0; int ret = 0; llcc_regmap = syscon_node_to_regmap(dev->of_node); Loading @@ -77,7 +74,14 @@ static int qcom_llcc_core_probe(struct platform_device *pdev) return PTR_ERR(llcc_regmap); } qcom_llcc_core_setup(llcc_regmap); ret = of_property_read_u32(dev->of_node, "qcom,llcc-broadcast-off", &b_off); if (ret) { dev_err(&pdev->dev, "Unable to read broadcast-off\n"); return -EINVAL; } qcom_llcc_core_setup(llcc_regmap, b_off); return 0; } Loading
drivers/soc/qcom/llcc-slice.c +16 −5 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ #define CACHE_LINE_SIZE_SHIFT 6 #define SIZE_PER_LLCC_SHIFT 2 #define MAX_CAP_TO_BYTES(n) (n * 1024) #define LLCC_TRP_ACT_CTRLn(n) (n * 0x1000) #define LLCC_TRP_STATUSn(n) (4 + n * 0x1000) Loading @@ -63,6 +64,7 @@ struct llcc_drv_data { struct mutex slice_mutex; u32 llcc_config_data_sz; u32 max_slices; u32 b_off; unsigned long *llcc_slice_map; }; Loading Loading @@ -172,8 +174,8 @@ static int llcc_update_act_ctrl(struct llcc_drv_data *drv, u32 sid, u32 slice_status; unsigned long timeout; act_ctrl_reg = LLCC_TRP_ACT_CTRLn(sid); status_reg = LLCC_TRP_STATUSn(sid); act_ctrl_reg = drv->b_off + LLCC_TRP_ACT_CTRLn(sid); status_reg = drv->b_off + LLCC_TRP_STATUSn(sid); regmap_write(drv->llcc_map, act_ctrl_reg, act_ctrl_reg_val); Loading Loading @@ -323,13 +325,14 @@ static void qcom_llcc_cfg_program(struct platform_device *pdev) const struct llcc_slice_config *llcc_table; struct llcc_drv_data *drv = platform_get_drvdata(pdev); struct llcc_slice_desc desc; u32 b_off = drv->b_off; sz = drv->llcc_config_data_sz; llcc_table = drv->slice_data; for (i = 0; i < sz; i++) { attr1_cfg = LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id); attr0_cfg = LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id); attr1_cfg = b_off + LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id); attr0_cfg = b_off + LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id); attr1_val = llcc_table[i].cache_mode; attr1_val |= (llcc_table[i].probe_target_ways << Loading Loading @@ -386,7 +389,15 @@ int qcom_llcc_probe(struct platform_device *pdev, rc = of_property_read_u32(pdev->dev.of_node, "max-slices", &drv_data->max_slices); if (rc) { dev_info(&pdev->dev, "Invalid max-slices dt entry\n"); dev_err(&pdev->dev, "Invalid max-slices dt entry\n"); devm_kfree(&pdev->dev, drv_data); return rc; } rc = of_property_read_u32(pdev->dev.parent->of_node, "qcom,llcc-broadcast-off", &drv_data->b_off); if (rc) { dev_err(&pdev->dev, "Invalid qcom,broadcast-off entry\n"); devm_kfree(&pdev->dev, drv_data); return rc; } Loading