Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

EDAC/qcom: Get rid of hardcoded register offsets

The LLCC EDAC register offsets varies between each SoC. Hardcoding the
register offsets won't work and will often result in crash due to
accessing the wrong locations.

Hence, get the register offsets from the LLCC driver matching the
individual SoCs.

Cc: <stable@vger.kernel.org> # 6.0: 5365cea199c7 ("soc: qcom: llcc: Rename reg_offset structs to reflect LLCC version")
Cc: <stable@vger.kernel.org> # 6.0: c13d7d261e36 ("soc: qcom: llcc: Pass LLCC version based register offsets to EDAC driver")
Cc: <stable@vger.kernel.org> # 6.0
Fixes: a6e9d7ef252c ("soc: qcom: llcc: Add configuration data for SM8450 SoC")
Acked-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/20230517114635.76358-3-manivannan.sadhasivam@linaro.org

authored by

Manivannan Sadhasivam and committed by
Bjorn Andersson
cbd77119 3d49f740

+58 -64
+58 -58
drivers/edac/qcom_edac.c
··· 21 21 #define TRP_SYN_REG_CNT 6 22 22 #define DRP_SYN_REG_CNT 8 23 23 24 - #define LLCC_COMMON_STATUS0 0x0003000c 25 24 #define LLCC_LB_CNT_MASK GENMASK(31, 28) 26 25 #define LLCC_LB_CNT_SHIFT 28 27 - 28 - /* Single & double bit syndrome register offsets */ 29 - #define TRP_ECC_SB_ERR_SYN0 0x0002304c 30 - #define TRP_ECC_DB_ERR_SYN0 0x00020370 31 - #define DRP_ECC_SB_ERR_SYN0 0x0004204c 32 - #define DRP_ECC_DB_ERR_SYN0 0x00042070 33 - 34 - /* Error register offsets */ 35 - #define TRP_ECC_ERROR_STATUS1 0x00020348 36 - #define TRP_ECC_ERROR_STATUS0 0x00020344 37 - #define DRP_ECC_ERROR_STATUS1 0x00042048 38 - #define DRP_ECC_ERROR_STATUS0 0x00042044 39 - 40 - /* TRP, DRP interrupt register offsets */ 41 - #define DRP_INTERRUPT_STATUS 0x00041000 42 - #define TRP_INTERRUPT_0_STATUS 0x00020480 43 - #define DRP_INTERRUPT_CLEAR 0x00041008 44 - #define DRP_ECC_ERROR_CNTR_CLEAR 0x00040004 45 - #define TRP_INTERRUPT_0_CLEAR 0x00020484 46 - #define TRP_ECC_ERROR_CNTR_CLEAR 0x00020440 47 26 48 27 /* Mask and shift macros */ 49 28 #define ECC_DB_ERR_COUNT_MASK GENMASK(4, 0) ··· 38 59 39 60 #define DRP_TRP_INT_CLEAR GENMASK(1, 0) 40 61 #define DRP_TRP_CNT_CLEAR GENMASK(1, 0) 41 - 42 - /* Config registers offsets*/ 43 - #define DRP_ECC_ERROR_CFG 0x00040000 44 - 45 - /* Tag RAM, Data RAM interrupt register offsets */ 46 - #define CMN_INTERRUPT_0_ENABLE 0x0003001c 47 - #define CMN_INTERRUPT_2_ENABLE 0x0003003c 48 - #define TRP_INTERRUPT_0_ENABLE 0x00020488 49 - #define DRP_INTERRUPT_ENABLE 0x0004100c 50 62 51 63 #define SB_ERROR_THRESHOLD 0x1 52 64 #define SB_ERROR_THRESHOLD_SHIFT 24 ··· 58 88 static const struct llcc_edac_reg_data edac_reg_data[] = { 59 89 [LLCC_DRAM_CE] = { 60 90 .name = "DRAM Single-bit", 61 - .synd_reg = DRP_ECC_SB_ERR_SYN0, 62 - .count_status_reg = DRP_ECC_ERROR_STATUS1, 63 - .ways_status_reg = DRP_ECC_ERROR_STATUS0, 64 91 .reg_cnt = DRP_SYN_REG_CNT, 65 92 .count_mask = ECC_SB_ERR_COUNT_MASK, 66 93 .ways_mask = ECC_SB_ERR_WAYS_MASK, ··· 65 98 }, 66 99 [LLCC_DRAM_UE] = { 67 100 .name = "DRAM Double-bit", 68 - .synd_reg = DRP_ECC_DB_ERR_SYN0, 69 - .count_status_reg = DRP_ECC_ERROR_STATUS1, 70 - .ways_status_reg = DRP_ECC_ERROR_STATUS0, 71 101 .reg_cnt = DRP_SYN_REG_CNT, 72 102 .count_mask = ECC_DB_ERR_COUNT_MASK, 73 103 .ways_mask = ECC_DB_ERR_WAYS_MASK, ··· 72 108 }, 73 109 [LLCC_TRAM_CE] = { 74 110 .name = "TRAM Single-bit", 75 - .synd_reg = TRP_ECC_SB_ERR_SYN0, 76 - .count_status_reg = TRP_ECC_ERROR_STATUS1, 77 - .ways_status_reg = TRP_ECC_ERROR_STATUS0, 78 111 .reg_cnt = TRP_SYN_REG_CNT, 79 112 .count_mask = ECC_SB_ERR_COUNT_MASK, 80 113 .ways_mask = ECC_SB_ERR_WAYS_MASK, ··· 79 118 }, 80 119 [LLCC_TRAM_UE] = { 81 120 .name = "TRAM Double-bit", 82 - .synd_reg = TRP_ECC_DB_ERR_SYN0, 83 - .count_status_reg = TRP_ECC_ERROR_STATUS1, 84 - .ways_status_reg = TRP_ECC_ERROR_STATUS0, 85 121 .reg_cnt = TRP_SYN_REG_CNT, 86 122 .count_mask = ECC_DB_ERR_COUNT_MASK, 87 123 .ways_mask = ECC_DB_ERR_WAYS_MASK, ··· 86 128 }, 87 129 }; 88 130 89 - static int qcom_llcc_core_setup(struct regmap *llcc_bcast_regmap) 131 + static int qcom_llcc_core_setup(struct llcc_drv_data *drv, struct regmap *llcc_bcast_regmap) 90 132 { 91 133 u32 sb_err_threshold; 92 134 int ret; ··· 95 137 * Configure interrupt enable registers such that Tag, Data RAM related 96 138 * interrupts are propagated to interrupt controller for servicing 97 139 */ 98 - ret = regmap_update_bits(llcc_bcast_regmap, CMN_INTERRUPT_2_ENABLE, 140 + ret = regmap_update_bits(llcc_bcast_regmap, drv->edac_reg_offset->cmn_interrupt_2_enable, 99 141 TRP0_INTERRUPT_ENABLE, 100 142 TRP0_INTERRUPT_ENABLE); 101 143 if (ret) 102 144 return ret; 103 145 104 - ret = regmap_update_bits(llcc_bcast_regmap, TRP_INTERRUPT_0_ENABLE, 146 + ret = regmap_update_bits(llcc_bcast_regmap, drv->edac_reg_offset->trp_interrupt_0_enable, 105 147 SB_DB_TRP_INTERRUPT_ENABLE, 106 148 SB_DB_TRP_INTERRUPT_ENABLE); 107 149 if (ret) 108 150 return ret; 109 151 110 152 sb_err_threshold = (SB_ERROR_THRESHOLD << SB_ERROR_THRESHOLD_SHIFT); 111 - ret = regmap_write(llcc_bcast_regmap, DRP_ECC_ERROR_CFG, 153 + ret = regmap_write(llcc_bcast_regmap, drv->edac_reg_offset->drp_ecc_error_cfg, 112 154 sb_err_threshold); 113 155 if (ret) 114 156 return ret; 115 157 116 - ret = regmap_update_bits(llcc_bcast_regmap, CMN_INTERRUPT_2_ENABLE, 158 + ret = regmap_update_bits(llcc_bcast_regmap, drv->edac_reg_offset->cmn_interrupt_2_enable, 117 159 DRP0_INTERRUPT_ENABLE, 118 160 DRP0_INTERRUPT_ENABLE); 119 161 if (ret) 120 162 return ret; 121 163 122 - ret = regmap_write(llcc_bcast_regmap, DRP_INTERRUPT_ENABLE, 164 + ret = regmap_write(llcc_bcast_regmap, drv->edac_reg_offset->drp_interrupt_enable, 123 165 SB_DB_DRP_INTERRUPT_ENABLE); 124 166 return ret; 125 167 } ··· 133 175 switch (err_type) { 134 176 case LLCC_DRAM_CE: 135 177 case LLCC_DRAM_UE: 136 - ret = regmap_write(drv->bcast_regmap, DRP_INTERRUPT_CLEAR, 178 + ret = regmap_write(drv->bcast_regmap, 179 + drv->edac_reg_offset->drp_interrupt_clear, 137 180 DRP_TRP_INT_CLEAR); 138 181 if (ret) 139 182 return ret; 140 183 141 - ret = regmap_write(drv->bcast_regmap, DRP_ECC_ERROR_CNTR_CLEAR, 184 + ret = regmap_write(drv->bcast_regmap, 185 + drv->edac_reg_offset->drp_ecc_error_cntr_clear, 142 186 DRP_TRP_CNT_CLEAR); 143 187 if (ret) 144 188 return ret; 145 189 break; 146 190 case LLCC_TRAM_CE: 147 191 case LLCC_TRAM_UE: 148 - ret = regmap_write(drv->bcast_regmap, TRP_INTERRUPT_0_CLEAR, 192 + ret = regmap_write(drv->bcast_regmap, 193 + drv->edac_reg_offset->trp_interrupt_0_clear, 149 194 DRP_TRP_INT_CLEAR); 150 195 if (ret) 151 196 return ret; 152 197 153 - ret = regmap_write(drv->bcast_regmap, TRP_ECC_ERROR_CNTR_CLEAR, 198 + ret = regmap_write(drv->bcast_regmap, 199 + drv->edac_reg_offset->trp_ecc_error_cntr_clear, 154 200 DRP_TRP_CNT_CLEAR); 155 201 if (ret) 156 202 return ret; ··· 167 205 return ret; 168 206 } 169 207 208 + struct qcom_llcc_syn_regs { 209 + u32 synd_reg; 210 + u32 count_status_reg; 211 + u32 ways_status_reg; 212 + }; 213 + 214 + static void get_reg_offsets(struct llcc_drv_data *drv, int err_type, 215 + struct qcom_llcc_syn_regs *syn_regs) 216 + { 217 + const struct llcc_edac_reg_offset *edac_reg_offset = drv->edac_reg_offset; 218 + 219 + switch (err_type) { 220 + case LLCC_DRAM_CE: 221 + syn_regs->synd_reg = edac_reg_offset->drp_ecc_sb_err_syn0; 222 + syn_regs->count_status_reg = edac_reg_offset->drp_ecc_error_status1; 223 + syn_regs->ways_status_reg = edac_reg_offset->drp_ecc_error_status0; 224 + break; 225 + case LLCC_DRAM_UE: 226 + syn_regs->synd_reg = edac_reg_offset->drp_ecc_db_err_syn0; 227 + syn_regs->count_status_reg = edac_reg_offset->drp_ecc_error_status1; 228 + syn_regs->ways_status_reg = edac_reg_offset->drp_ecc_error_status0; 229 + break; 230 + case LLCC_TRAM_CE: 231 + syn_regs->synd_reg = edac_reg_offset->trp_ecc_sb_err_syn0; 232 + syn_regs->count_status_reg = edac_reg_offset->trp_ecc_error_status1; 233 + syn_regs->ways_status_reg = edac_reg_offset->trp_ecc_error_status0; 234 + break; 235 + case LLCC_TRAM_UE: 236 + syn_regs->synd_reg = edac_reg_offset->trp_ecc_db_err_syn0; 237 + syn_regs->count_status_reg = edac_reg_offset->trp_ecc_error_status1; 238 + syn_regs->ways_status_reg = edac_reg_offset->trp_ecc_error_status0; 239 + break; 240 + } 241 + } 242 + 170 243 /* Dump Syndrome registers data for Tag RAM, Data RAM bit errors*/ 171 244 static int 172 245 dump_syn_reg_values(struct llcc_drv_data *drv, u32 bank, int err_type) 173 246 { 174 247 struct llcc_edac_reg_data reg_data = edac_reg_data[err_type]; 248 + struct qcom_llcc_syn_regs regs = { }; 175 249 int err_cnt, err_ways, ret, i; 176 250 u32 synd_reg, synd_val; 177 251 252 + get_reg_offsets(drv, err_type, &regs); 253 + 178 254 for (i = 0; i < reg_data.reg_cnt; i++) { 179 - synd_reg = reg_data.synd_reg + (i * 4); 255 + synd_reg = regs.synd_reg + (i * 4); 180 256 ret = regmap_read(drv->regmaps[bank], synd_reg, 181 257 &synd_val); 182 258 if (ret) ··· 224 224 reg_data.name, i, synd_val); 225 225 } 226 226 227 - ret = regmap_read(drv->regmaps[bank], reg_data.count_status_reg, 227 + ret = regmap_read(drv->regmaps[bank], regs.count_status_reg, 228 228 &err_cnt); 229 229 if (ret) 230 230 goto clear; ··· 234 234 edac_printk(KERN_CRIT, EDAC_LLCC, "%s: Error count: 0x%4x\n", 235 235 reg_data.name, err_cnt); 236 236 237 - ret = regmap_read(drv->regmaps[bank], reg_data.ways_status_reg, 237 + ret = regmap_read(drv->regmaps[bank], regs.ways_status_reg, 238 238 &err_ways); 239 239 if (ret) 240 240 goto clear; ··· 295 295 296 296 /* Iterate over the banks and look for Tag RAM or Data RAM errors */ 297 297 for (i = 0; i < drv->num_banks; i++) { 298 - ret = regmap_read(drv->regmaps[i], DRP_INTERRUPT_STATUS, 298 + ret = regmap_read(drv->regmaps[i], drv->edac_reg_offset->drp_interrupt_status, 299 299 &drp_error); 300 300 301 301 if (!ret && (drp_error & SB_ECC_ERROR)) { ··· 310 310 if (!ret) 311 311 irq_rc = IRQ_HANDLED; 312 312 313 - ret = regmap_read(drv->regmaps[i], TRP_INTERRUPT_0_STATUS, 313 + ret = regmap_read(drv->regmaps[i], drv->edac_reg_offset->trp_interrupt_0_status, 314 314 &trp_error); 315 315 316 316 if (!ret && (trp_error & SB_ECC_ERROR)) { ··· 342 342 int ecc_irq; 343 343 int rc; 344 344 345 - rc = qcom_llcc_core_setup(llcc_driv_data->bcast_regmap); 345 + rc = qcom_llcc_core_setup(llcc_driv_data, llcc_driv_data->bcast_regmap); 346 346 if (rc) 347 347 return rc; 348 348
-6
include/linux/soc/qcom/llcc-qcom.h
··· 69 69 /** 70 70 * struct llcc_edac_reg_data - llcc edac registers data for each error type 71 71 * @name: Name of the error 72 - * @synd_reg: Syndrome register address 73 - * @count_status_reg: Status register address to read the error count 74 - * @ways_status_reg: Status register address to read the error ways 75 72 * @reg_cnt: Number of registers 76 73 * @count_mask: Mask value to get the error count 77 74 * @ways_mask: Mask value to get the error ways ··· 77 80 */ 78 81 struct llcc_edac_reg_data { 79 82 char *name; 80 - u64 synd_reg; 81 - u64 count_status_reg; 82 - u64 ways_status_reg; 83 83 u32 reg_cnt; 84 84 u32 count_mask; 85 85 u32 ways_mask;