1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
6 #include <linux/edac.h>
7 #include <linux/interrupt.h>
8 #include <linux/kernel.h>
10 #include <linux/platform_device.h>
11 #include <linux/regmap.h>
12 #include <linux/soc/qcom/llcc-qcom.h>
15 #include "edac_device.h"
17 #define EDAC_LLCC "qcom_llcc"
19 #define LLCC_ERP_PANIC_ON_UE 1
21 #define TRP_SYN_REG_CNT 6
22 #define DRP_SYN_REG_CNT 8
24 #define LLCC_LB_CNT_MASK GENMASK(31, 28)
25 #define LLCC_LB_CNT_SHIFT 28
27 /* Mask and shift macros */
28 #define ECC_DB_ERR_COUNT_MASK GENMASK(4, 0)
29 #define ECC_DB_ERR_WAYS_MASK GENMASK(31, 16)
30 #define ECC_DB_ERR_WAYS_SHIFT BIT(4)
32 #define ECC_SB_ERR_COUNT_MASK GENMASK(23, 16)
33 #define ECC_SB_ERR_COUNT_SHIFT BIT(4)
34 #define ECC_SB_ERR_WAYS_MASK GENMASK(15, 0)
36 #define SB_ECC_ERROR BIT(0)
37 #define DB_ECC_ERROR BIT(1)
39 #define DRP_TRP_INT_CLEAR GENMASK(1, 0)
40 #define DRP_TRP_CNT_CLEAR GENMASK(1, 0)
42 #define SB_ERROR_THRESHOLD 0x1
43 #define SB_ERROR_THRESHOLD_SHIFT 24
44 #define SB_DB_TRP_INTERRUPT_ENABLE 0x3
45 #define TRP0_INTERRUPT_ENABLE 0x1
46 #define DRP0_INTERRUPT_ENABLE BIT(6)
47 #define SB_DB_DRP_INTERRUPT_ENABLE 0x3
49 #define ECC_POLL_MSEC 5000
58 static const struct llcc_edac_reg_data edac_reg_data
[] = {
60 .name
= "DRAM Single-bit",
61 .reg_cnt
= DRP_SYN_REG_CNT
,
62 .count_mask
= ECC_SB_ERR_COUNT_MASK
,
63 .ways_mask
= ECC_SB_ERR_WAYS_MASK
,
64 .count_shift
= ECC_SB_ERR_COUNT_SHIFT
,
67 .name
= "DRAM Double-bit",
68 .reg_cnt
= DRP_SYN_REG_CNT
,
69 .count_mask
= ECC_DB_ERR_COUNT_MASK
,
70 .ways_mask
= ECC_DB_ERR_WAYS_MASK
,
71 .ways_shift
= ECC_DB_ERR_WAYS_SHIFT
,
74 .name
= "TRAM Single-bit",
75 .reg_cnt
= TRP_SYN_REG_CNT
,
76 .count_mask
= ECC_SB_ERR_COUNT_MASK
,
77 .ways_mask
= ECC_SB_ERR_WAYS_MASK
,
78 .count_shift
= ECC_SB_ERR_COUNT_SHIFT
,
81 .name
= "TRAM Double-bit",
82 .reg_cnt
= TRP_SYN_REG_CNT
,
83 .count_mask
= ECC_DB_ERR_COUNT_MASK
,
84 .ways_mask
= ECC_DB_ERR_WAYS_MASK
,
85 .ways_shift
= ECC_DB_ERR_WAYS_SHIFT
,
89 static int qcom_llcc_core_setup(struct llcc_drv_data
*drv
, struct regmap
*llcc_bcast_regmap
)
95 * Configure interrupt enable registers such that Tag, Data RAM related
96 * interrupts are propagated to interrupt controller for servicing
98 ret
= regmap_update_bits(llcc_bcast_regmap
, drv
->edac_reg_offset
->cmn_interrupt_2_enable
,
99 TRP0_INTERRUPT_ENABLE
,
100 TRP0_INTERRUPT_ENABLE
);
104 ret
= regmap_update_bits(llcc_bcast_regmap
, drv
->edac_reg_offset
->trp_interrupt_0_enable
,
105 SB_DB_TRP_INTERRUPT_ENABLE
,
106 SB_DB_TRP_INTERRUPT_ENABLE
);
110 sb_err_threshold
= (SB_ERROR_THRESHOLD
<< SB_ERROR_THRESHOLD_SHIFT
);
111 ret
= regmap_write(llcc_bcast_regmap
, drv
->edac_reg_offset
->drp_ecc_error_cfg
,
116 ret
= regmap_update_bits(llcc_bcast_regmap
, drv
->edac_reg_offset
->cmn_interrupt_2_enable
,
117 DRP0_INTERRUPT_ENABLE
,
118 DRP0_INTERRUPT_ENABLE
);
122 ret
= regmap_write(llcc_bcast_regmap
, drv
->edac_reg_offset
->drp_interrupt_enable
,
123 SB_DB_DRP_INTERRUPT_ENABLE
);
127 /* Clear the error interrupt and counter registers */
129 qcom_llcc_clear_error_status(int err_type
, struct llcc_drv_data
*drv
)
136 ret
= regmap_write(drv
->bcast_regmap
,
137 drv
->edac_reg_offset
->drp_interrupt_clear
,
142 ret
= regmap_write(drv
->bcast_regmap
,
143 drv
->edac_reg_offset
->drp_ecc_error_cntr_clear
,
150 ret
= regmap_write(drv
->bcast_regmap
,
151 drv
->edac_reg_offset
->trp_interrupt_0_clear
,
156 ret
= regmap_write(drv
->bcast_regmap
,
157 drv
->edac_reg_offset
->trp_ecc_error_cntr_clear
,
164 edac_printk(KERN_CRIT
, EDAC_LLCC
, "Unexpected error type: %d\n",
170 struct qcom_llcc_syn_regs
{
172 u32 count_status_reg
;
176 static void get_reg_offsets(struct llcc_drv_data
*drv
, int err_type
,
177 struct qcom_llcc_syn_regs
*syn_regs
)
179 const struct llcc_edac_reg_offset
*edac_reg_offset
= drv
->edac_reg_offset
;
183 syn_regs
->synd_reg
= edac_reg_offset
->drp_ecc_sb_err_syn0
;
184 syn_regs
->count_status_reg
= edac_reg_offset
->drp_ecc_error_status1
;
185 syn_regs
->ways_status_reg
= edac_reg_offset
->drp_ecc_error_status0
;
188 syn_regs
->synd_reg
= edac_reg_offset
->drp_ecc_db_err_syn0
;
189 syn_regs
->count_status_reg
= edac_reg_offset
->drp_ecc_error_status1
;
190 syn_regs
->ways_status_reg
= edac_reg_offset
->drp_ecc_error_status0
;
193 syn_regs
->synd_reg
= edac_reg_offset
->trp_ecc_sb_err_syn0
;
194 syn_regs
->count_status_reg
= edac_reg_offset
->trp_ecc_error_status1
;
195 syn_regs
->ways_status_reg
= edac_reg_offset
->trp_ecc_error_status0
;
198 syn_regs
->synd_reg
= edac_reg_offset
->trp_ecc_db_err_syn0
;
199 syn_regs
->count_status_reg
= edac_reg_offset
->trp_ecc_error_status1
;
200 syn_regs
->ways_status_reg
= edac_reg_offset
->trp_ecc_error_status0
;
205 /* Dump Syndrome registers data for Tag RAM, Data RAM bit errors*/
207 dump_syn_reg_values(struct llcc_drv_data
*drv
, u32 bank
, int err_type
)
209 struct llcc_edac_reg_data reg_data
= edac_reg_data
[err_type
];
210 struct qcom_llcc_syn_regs regs
= { };
211 int err_cnt
, err_ways
, ret
, i
;
212 u32 synd_reg
, synd_val
;
214 get_reg_offsets(drv
, err_type
, ®s
);
216 for (i
= 0; i
< reg_data
.reg_cnt
; i
++) {
217 synd_reg
= regs
.synd_reg
+ (i
* 4);
218 ret
= regmap_read(drv
->regmaps
[bank
], synd_reg
,
223 edac_printk(KERN_CRIT
, EDAC_LLCC
, "%s: ECC_SYN%d: 0x%8x\n",
224 reg_data
.name
, i
, synd_val
);
227 ret
= regmap_read(drv
->regmaps
[bank
], regs
.count_status_reg
,
232 err_cnt
&= reg_data
.count_mask
;
233 err_cnt
>>= reg_data
.count_shift
;
234 edac_printk(KERN_CRIT
, EDAC_LLCC
, "%s: Error count: 0x%4x\n",
235 reg_data
.name
, err_cnt
);
237 ret
= regmap_read(drv
->regmaps
[bank
], regs
.ways_status_reg
,
242 err_ways
&= reg_data
.ways_mask
;
243 err_ways
>>= reg_data
.ways_shift
;
245 edac_printk(KERN_CRIT
, EDAC_LLCC
, "%s: Error ways: 0x%4x\n",
246 reg_data
.name
, err_ways
);
249 return qcom_llcc_clear_error_status(err_type
, drv
);
253 dump_syn_reg(struct edac_device_ctl_info
*edev_ctl
, int err_type
, u32 bank
)
255 struct llcc_drv_data
*drv
= edev_ctl
->dev
->platform_data
;
258 ret
= dump_syn_reg_values(drv
, bank
, err_type
);
264 edac_device_handle_ce(edev_ctl
, 0, bank
,
265 "LLCC Data RAM correctable Error");
268 edac_device_handle_ue(edev_ctl
, 0, bank
,
269 "LLCC Data RAM uncorrectable Error");
272 edac_device_handle_ce(edev_ctl
, 0, bank
,
273 "LLCC Tag RAM correctable Error");
276 edac_device_handle_ue(edev_ctl
, 0, bank
,
277 "LLCC Tag RAM uncorrectable Error");
281 edac_printk(KERN_CRIT
, EDAC_LLCC
, "Unexpected error type: %d\n",
288 static irqreturn_t
llcc_ecc_irq_handler(int irq
, void *edev_ctl
)
290 struct edac_device_ctl_info
*edac_dev_ctl
= edev_ctl
;
291 struct llcc_drv_data
*drv
= edac_dev_ctl
->dev
->platform_data
;
292 irqreturn_t irq_rc
= IRQ_NONE
;
293 u32 drp_error
, trp_error
, i
;
296 /* Iterate over the banks and look for Tag RAM or Data RAM errors */
297 for (i
= 0; i
< drv
->num_banks
; i
++) {
298 ret
= regmap_read(drv
->regmaps
[i
], drv
->edac_reg_offset
->drp_interrupt_status
,
301 if (!ret
&& (drp_error
& SB_ECC_ERROR
)) {
302 edac_printk(KERN_CRIT
, EDAC_LLCC
,
303 "Single Bit Error detected in Data RAM\n");
304 ret
= dump_syn_reg(edev_ctl
, LLCC_DRAM_CE
, i
);
305 } else if (!ret
&& (drp_error
& DB_ECC_ERROR
)) {
306 edac_printk(KERN_CRIT
, EDAC_LLCC
,
307 "Double Bit Error detected in Data RAM\n");
308 ret
= dump_syn_reg(edev_ctl
, LLCC_DRAM_UE
, i
);
311 irq_rc
= IRQ_HANDLED
;
313 ret
= regmap_read(drv
->regmaps
[i
], drv
->edac_reg_offset
->trp_interrupt_0_status
,
316 if (!ret
&& (trp_error
& SB_ECC_ERROR
)) {
317 edac_printk(KERN_CRIT
, EDAC_LLCC
,
318 "Single Bit Error detected in Tag RAM\n");
319 ret
= dump_syn_reg(edev_ctl
, LLCC_TRAM_CE
, i
);
320 } else if (!ret
&& (trp_error
& DB_ECC_ERROR
)) {
321 edac_printk(KERN_CRIT
, EDAC_LLCC
,
322 "Double Bit Error detected in Tag RAM\n");
323 ret
= dump_syn_reg(edev_ctl
, LLCC_TRAM_UE
, i
);
326 irq_rc
= IRQ_HANDLED
;
332 static void llcc_ecc_check(struct edac_device_ctl_info
*edev_ctl
)
334 llcc_ecc_irq_handler(0, edev_ctl
);
337 static int qcom_llcc_edac_probe(struct platform_device
*pdev
)
339 struct llcc_drv_data
*llcc_driv_data
= pdev
->dev
.platform_data
;
340 struct edac_device_ctl_info
*edev_ctl
;
341 struct device
*dev
= &pdev
->dev
;
345 if (!llcc_driv_data
->ecc_irq_configured
) {
346 rc
= qcom_llcc_core_setup(llcc_driv_data
, llcc_driv_data
->bcast_regmap
);
351 /* Allocate edac control info */
352 edev_ctl
= edac_device_alloc_ctl_info(0, "qcom-llcc", 1, "bank",
353 llcc_driv_data
->num_banks
, 1,
354 edac_device_alloc_index());
360 edev_ctl
->mod_name
= dev_name(dev
);
361 edev_ctl
->dev_name
= dev_name(dev
);
362 edev_ctl
->ctl_name
= "llcc";
363 edev_ctl
->panic_on_ue
= LLCC_ERP_PANIC_ON_UE
;
365 /* Check if LLCC driver has passed ECC IRQ */
366 ecc_irq
= llcc_driv_data
->ecc_irq
;
368 /* Use interrupt mode if IRQ is available */
369 rc
= devm_request_irq(dev
, ecc_irq
, llcc_ecc_irq_handler
,
370 IRQF_TRIGGER_HIGH
, "llcc_ecc", edev_ctl
);
372 edac_op_state
= EDAC_OPSTATE_INT
;
377 /* Fall back to polling mode otherwise */
378 edev_ctl
->poll_msec
= ECC_POLL_MSEC
;
379 edev_ctl
->edac_check
= llcc_ecc_check
;
380 edac_op_state
= EDAC_OPSTATE_POLL
;
383 rc
= edac_device_add_device(edev_ctl
);
385 edac_device_free_ctl_info(edev_ctl
);
389 platform_set_drvdata(pdev
, edev_ctl
);
394 static void qcom_llcc_edac_remove(struct platform_device
*pdev
)
396 struct edac_device_ctl_info
*edev_ctl
= dev_get_drvdata(&pdev
->dev
);
398 edac_device_del_device(edev_ctl
->dev
);
399 edac_device_free_ctl_info(edev_ctl
);
402 static const struct platform_device_id qcom_llcc_edac_id_table
[] = {
403 { .name
= "qcom_llcc_edac" },
406 MODULE_DEVICE_TABLE(platform
, qcom_llcc_edac_id_table
);
408 static struct platform_driver qcom_llcc_edac_driver
= {
409 .probe
= qcom_llcc_edac_probe
,
410 .remove
= qcom_llcc_edac_remove
,
412 .name
= "qcom_llcc_edac",
414 .id_table
= qcom_llcc_edac_id_table
,
416 module_platform_driver(qcom_llcc_edac_driver
);
418 MODULE_DESCRIPTION("QCOM EDAC driver");
419 MODULE_LICENSE("GPL v2");