drivers/edac/qcom_edac.c

Source file repositories/reference/linux-study-clean/drivers/edac/qcom_edac.c

File Facts

System
Linux kernel
Corpus path
drivers/edac/qcom_edac.c
Extension
.c
Size
11529 bytes
Lines
420
Domain
Driver Families
Bucket
drivers/edac
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct qcom_llcc_syn_regs {
	u32 synd_reg;
	u32 count_status_reg;
	u32 ways_status_reg;
};

static void get_reg_offsets(struct llcc_drv_data *drv, int err_type,
			    struct qcom_llcc_syn_regs *syn_regs)
{
	const struct llcc_edac_reg_offset *edac_reg_offset = drv->edac_reg_offset;

	switch (err_type) {
	case LLCC_DRAM_CE:
		syn_regs->synd_reg = edac_reg_offset->drp_ecc_sb_err_syn0;
		syn_regs->count_status_reg = edac_reg_offset->drp_ecc_error_status1;
		syn_regs->ways_status_reg = edac_reg_offset->drp_ecc_error_status0;
		break;
	case LLCC_DRAM_UE:
		syn_regs->synd_reg = edac_reg_offset->drp_ecc_db_err_syn0;
		syn_regs->count_status_reg = edac_reg_offset->drp_ecc_error_status1;
		syn_regs->ways_status_reg = edac_reg_offset->drp_ecc_error_status0;
		break;
	case LLCC_TRAM_CE:
		syn_regs->synd_reg = edac_reg_offset->trp_ecc_sb_err_syn0;
		syn_regs->count_status_reg = edac_reg_offset->trp_ecc_error_status1;
		syn_regs->ways_status_reg = edac_reg_offset->trp_ecc_error_status0;
		break;
	case LLCC_TRAM_UE:
		syn_regs->synd_reg = edac_reg_offset->trp_ecc_db_err_syn0;
		syn_regs->count_status_reg = edac_reg_offset->trp_ecc_error_status1;
		syn_regs->ways_status_reg = edac_reg_offset->trp_ecc_error_status0;
		break;
	}
}

/* Dump Syndrome registers data for Tag RAM, Data RAM bit errors*/
static int
dump_syn_reg_values(struct llcc_drv_data *drv, u32 bank, int err_type)
{
	struct llcc_edac_reg_data reg_data = edac_reg_data[err_type];
	struct qcom_llcc_syn_regs regs = { };
	int err_cnt, err_ways, ret, i;
	u32 synd_reg, synd_val;

	get_reg_offsets(drv, err_type, &regs);

	for (i = 0; i < reg_data.reg_cnt; i++) {
		synd_reg = regs.synd_reg + (i * 4);
		ret = regmap_read(drv->regmaps[bank], synd_reg,
				  &synd_val);
		if (ret)
			goto clear;

		edac_printk(KERN_CRIT, EDAC_LLCC, "%s: ECC_SYN%d: 0x%8x\n",
			    reg_data.name, i, synd_val);
	}

	ret = regmap_read(drv->regmaps[bank], regs.count_status_reg,
			  &err_cnt);
	if (ret)
		goto clear;

	err_cnt &= reg_data.count_mask;
	err_cnt >>= reg_data.count_shift;
	edac_printk(KERN_CRIT, EDAC_LLCC, "%s: Error count: 0x%4x\n",
		    reg_data.name, err_cnt);

	ret = regmap_read(drv->regmaps[bank], regs.ways_status_reg,
			  &err_ways);
	if (ret)
		goto clear;

	err_ways &= reg_data.ways_mask;
	err_ways >>= reg_data.ways_shift;

	edac_printk(KERN_CRIT, EDAC_LLCC, "%s: Error ways: 0x%4x\n",
		    reg_data.name, err_ways);

clear:
	return qcom_llcc_clear_error_status(err_type, drv);
}

static int
dump_syn_reg(struct edac_device_ctl_info *edev_ctl, int err_type, u32 bank)
{
	struct llcc_drv_data *drv = edev_ctl->dev->platform_data;
	int ret;

	ret = dump_syn_reg_values(drv, bank, err_type);
	if (ret)

Annotation

Implementation Notes