drivers/edac/skx_common.c

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

File Facts

System
Linux kernel
Corpus path
drivers/edac/skx_common.c
Extension
.c
Size
30141 bytes
Lines
1184
Domain
Driver Families
Bucket
drivers/edac
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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

if (first) {
			if (!(*rrl_ctl & rrl->noover_mask))
				v &= ~rrl->noover_mask;
		} else {
			if (*rrl_ctl & rrl->noover_mask)
				v |= rrl->noover_mask;
		}

		if (scrub) {
			if (!(*rrl_ctl & rrl->en_patspr_mask))
				v &= ~rrl->en_patspr_mask;
		} else {
			if (*rrl_ctl & rrl->en_patspr_mask)
				v |= rrl->en_patspr_mask;
		}

		if (!(*rrl_ctl & rrl->en_mask))
			v &= ~rrl->en_mask;
	}

	skx_write_imc_reg(imc, chan, offset, width, v);
}

static void enable_rrls(struct skx_imc *imc, int chan, struct reg_rrl *rrl,
			bool enable, u32 *rrl_ctl)
{
	for (int i = 0; i < rrl->set_num; i++)
		enable_rrl(imc, chan, rrl, i, enable, rrl_ctl + i);
}

static void enable_rrls_ddr(struct skx_imc *imc, bool enable)
{
	struct reg_rrl **rrl_ddr = skx_res_cfg->reg_rrl_ddr;
	int i, chan_num = skx_res_cfg->ddr_chan_num;
	struct skx_channel *chan = imc->chan;

	if (!imc->mbase)
		return;

	for (i = 0; i < chan_num; i++) {
		enable_rrls(imc, i, rrl_ddr[0], enable, chan[i].rrl_ctl[0]);
		if (rrl_ddr[1])
			enable_rrls(imc, i, rrl_ddr[1], enable, chan[i].rrl_ctl[1]);
	}
}

static void enable_rrls_hbm(struct skx_imc *imc, bool enable)
{
	struct reg_rrl **rrl_hbm = skx_res_cfg->reg_rrl_hbm;
	int i, chan_num = skx_res_cfg->hbm_chan_num;
	struct skx_channel *chan = imc->chan;

	if (!imc->mbase || !imc->hbm_mc || !rrl_hbm[0] || !rrl_hbm[1])
		return;

	for (i = 0; i < chan_num; i++) {
		enable_rrls(imc, i, rrl_hbm[0], enable, chan[i].rrl_ctl[0]);
		enable_rrls(imc, i, rrl_hbm[1], enable, chan[i].rrl_ctl[1]);
	}
}

void skx_enable_rrl(bool enable)
{
	struct skx_dev *d;
	int i, imc_num;

	edac_dbg(2, "\n");

	list_for_each_entry(d, &dev_edac_list, list) {
		imc_num  = skx_res_cfg->ddr_imc_num;
		for (i = 0; i < imc_num; i++)
			enable_rrls_ddr(&d->imc[i], enable);

		imc_num += skx_res_cfg->hbm_imc_num;
		for (; i < imc_num; i++)
			enable_rrls_hbm(&d->imc[i], enable);
	}
}
EXPORT_SYMBOL_GPL(skx_enable_rrl);

static struct reg_rrl *get_rrl_reg(struct decoded_addr *res, struct res_config *cfg)
{
	struct skx_imc *imc = &res->dev->imc[res->imc];

	/* HBM has two groups of RRL sets, one per pseudo-channel. */
	if (imc->hbm_mc)
		return cfg->reg_rrl_hbm[res->cs & 1];

	/* One group of RRL sets per DDR channel. */
	if (!cfg->reg_rrl_ddr[1])

Annotation

Implementation Notes