- Fix a malformed Kconfig default for the AMD Address Translation Library

- Make sure i10nm loads successfully when the ADXL address decoder is absent
   because former has decoding capabilities too
 
 - Ensure error reporting is cleanly disabled on driver teardown and on failed
   initialization for several legacy Intel EDAC drivers
 
 - Fix a grammar issue in a diagnostic warning in the Sandy Bridge driver
 
 - Fix a missing resource release callback and incorrect memory topology
   parsing in the igen6 driver, and add support for Intel Panther Lake-H and
   Nova Lake-H SoCs
 
 - Fix an out-of-bounds shift causing undefined behaviour in the Skylake
   driver
 
 - Consolidate memory controller register access helpers into shared common
   code across the Intel Skylake, Ice Lake, and Meteor Lake drivers
 
 - Introduce sub-channel awareness and Rank Retry Logic improvements to
   the Intel Skylake and i10nm drivers in preparation for Diamond Rapids
   server support
 
 - Add Rank Retry Logic support for Intel Diamond Rapids server to
   imh_edac
 
 - Make In-Band ECC detection registers configurable per SoC in the igen6
   driver
 
 - Standardize PCI device ID table definitions across all EDAC drivers to
   use named field initializers and standard PCI helper macros
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEzv7L6UO9uDPlPSfHEsHwGGHeVUoFAmovc4AACgkQEsHwGGHe
 VUqnzhAAmgpZ1hrzP/yzhKs3ThDHrU4wacmmVKsV8ToNzuQ+4KtLty/faLIHx9kp
 fJri2FWXQwY4Y9L5ZWB6vf/zQJG8mjJAoMFuexpJ2Fw+8BWUYTJOdD7FayG0v3ck
 x+cVPe57toVxsvmZAO4hBcdacOf7vss9c0ceVtAOqS1GXYsGLTcBg2y71stCBr4q
 +aOjM4dXh7sR5RYIOijacYEs1p5UNXmzUZbtChW0zHJ0dJF+U8psO+cU3cMKFRzt
 EhCEI6i4z2iemWA3KIEy9zXtOzoSj96/8g+SIeNrhIs5ANtDjTXu/5nBGPbvw0xV
 ndsMvetv3EqrvI472rRUL4A00WLtYMfeB69kBFyGDEmqRutpesqW6d7zTqq5p2qB
 dbNycPQur2Qj3yMEzOMxTpT+98fxKEg/S0hJ4lxJPdcuVxdhuPncR4ZNRPd5q40C
 veJt17pAn4FQOMCWyjReJdK5rBlmM716Osd4B2SNpG1JsQkmvVDeT6n6Xg1e03mZ
 MUvTH2fdegZOocfSK5i6hlhmn8mYPNRUrsnh565ivxDhrpT7ffiJoqHUBYqAcYnm
 5o9WEgYjtxcncyyVkf0KmWLuJGWMJ2xxAVE6zXhNW0pP2/FDYWcDVGdTUV9oKS7t
 1vY/rM+6GYNf6cSXW4F54SmUJuaCkSUn2Nhucf9lKmE3GBu/8Rs=
 =WiqU
 -----END PGP SIGNATURE-----

Merge tag 'edac_updates_for_v7.2_rc1' of gitolite.kernel.org:pub/scm/linux/kernel/git/ras/ras

Pull EDAC updates from Borislav Petkov:

 - Fix a malformed Kconfig default for the AMD Address Translation
   Library

 - Make sure i10nm loads successfully when the ADXL address decoder is
   absent because former has decoding capabilities too

 - Ensure error reporting is cleanly disabled on driver teardown and on
   failed initialization for several legacy Intel EDAC drivers

 - Fix a grammar issue in a diagnostic warning in the Sandy Bridge
   driver

 - Fix a missing resource release callback and incorrect memory topology
   parsing in the igen6 driver, and add support for Intel Panther Lake-H
   and Nova Lake-H SoCs

 - Fix an out-of-bounds shift causing undefined behaviour in the Skylake
   driver

 - Consolidate memory controller register access helpers into shared
   common code across the Intel Skylake, Ice Lake, and Meteor Lake
   drivers

 - Introduce sub-channel awareness and Rank Retry Logic improvements to
   the Intel Skylake and i10nm drivers in preparation for Diamond Rapids
   server support

 - Add Rank Retry Logic support for Intel Diamond Rapids server to
   imh_edac

 - Make In-Band ECC detection registers configurable per SoC in the
   igen6 driver

 - Standardize PCI device ID table definitions across all EDAC drivers
   to use named field initializers and standard PCI helper macros

* tag 'edac_updates_for_v7.2_rc1' of gitolite.kernel.org:pub/scm/linux/kernel/git/ras/ras: (22 commits)
  EDAC: Consistently define pci_device_ids using named initializers
  EDAC/igen6: Add Intel Nova Lake-H SoC support
  EDAC/igen6: Make registers for detecting IBECC configurable
  EDAC/imh: Add RRL support for Intel Diamond Rapids server
  EDAC/{skx_common,i10nm}: Prepare RRL for sub-channel granularity
  EDAC/skx_common: Add SubChannel support to ADXL decode
  EDAC/{skx_common,i10nm}: Move RRL handling to common code
  EDAC/{skx_common,i10nm}: Introduce rrl_ctrl_mode
  EDAC/{skx_common,i10nm}: Rename rrl_mode to rrl_source_type
  EDAC/{skx_common,skx,i10nm}: Split skx_set_decode()
  EDAC/{skx_common,i10nm,imh}: Move MC register access helpers to skx_common
  EDAC/{skx_common,skx}: Fix UBSAN shift-out-of-bounds in skx_get_dimm_info
  EDAC/igen6: Add one Intel Panther Lake-H SoC support
  EDAC/igen6: Fix memory topology parsing for Panther Lake-H SoCs
  EDAC/igen6: Fix call trace due to missing release()
  EDAC/sb_edac: fix grammar in sb_decode_ddr3 warning
  EDAC/i5400: disable error reporting at teardown and refactor helper
  EDAC/i5100: disable error reporting at teardown and create helper
  EDAC/i5000: disable error reporting at teardown and refactor helper
  EDAC/i7300: disable error reporting if init fails and refactor helper
  ...
This commit is contained in:
Linus Torvalds 2026-06-16 05:31:01 +05:30
commit 4b5713ef2f
24 changed files with 1074 additions and 591 deletions

View File

@ -332,14 +332,14 @@ static void amd76x_remove_one(struct pci_dev *pdev)
static const struct pci_device_id amd76x_pci_tbl[] = {
{
PCI_VEND_DEV(AMD, FE_GATE_700C), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
AMD762},
{
PCI_VEND_DEV(AMD, FE_GATE_700E), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
AMD761},
{
0,
} /* 0 terminated list. */
PCI_VEND_DEV(AMD, FE_GATE_700C),
.driver_data = AMD762
}, {
PCI_VEND_DEV(AMD, FE_GATE_700E),
.driver_data = AMD761,
}, {
/* 0 terminated list. */
}
};
MODULE_DEVICE_TABLE(pci, amd76x_pci_tbl);

View File

@ -1414,20 +1414,20 @@ static void e752x_remove_one(struct pci_dev *pdev)
static const struct pci_device_id e752x_pci_tbl[] = {
{
PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
E7520},
{
PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
E7525},
{
PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
E7320},
{
PCI_VEND_DEV(INTEL, 3100_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
I3100},
{
0,
} /* 0 terminated list. */
PCI_VEND_DEV(INTEL, 7520_0),
.driver_data = E7520,
}, {
PCI_VEND_DEV(INTEL, 7525_0),
.driver_data = E7525,
}, {
PCI_VEND_DEV(INTEL, 7320_0),
.driver_data = E7320,
}, {
PCI_VEND_DEV(INTEL, 3100_0),
.driver_data = I3100,
}, {
/* 0 terminated list. */
}
};
MODULE_DEVICE_TABLE(pci, e752x_pci_tbl);

View File

@ -554,20 +554,20 @@ static void e7xxx_remove_one(struct pci_dev *pdev)
static const struct pci_device_id e7xxx_pci_tbl[] = {
{
PCI_VEND_DEV(INTEL, 7205_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
E7205},
{
PCI_VEND_DEV(INTEL, 7500_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
E7500},
{
PCI_VEND_DEV(INTEL, 7501_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
E7501},
{
PCI_VEND_DEV(INTEL, 7505_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
E7505},
{
0,
} /* 0 terminated list. */
PCI_VEND_DEV(INTEL, 7205_0),
.driver_data = E7205,
}, {
PCI_VEND_DEV(INTEL, 7500_0),
.driver_data = E7500,
}, {
PCI_VEND_DEV(INTEL, 7501_0),
.driver_data = E7501,
}, {
PCI_VEND_DEV(INTEL, 7505_0),
.driver_data = E7505
}, {
/* 0 terminated list. */
}
};
MODULE_DEVICE_TABLE(pci, e7xxx_pci_tbl);

View File

@ -88,8 +88,8 @@ do { \
#endif /* !CONFIG_EDAC_DEBUG */
#define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, \
PCI_DEVICE_ID_ ## vend ## _ ## dev
#define PCI_VEND_DEV(vend, dev) \
PCI_DEVICE(PCI_VENDOR_ID_ ## vend, PCI_DEVICE_ID_ ## vend ## _ ## dev)
#define edac_dev_name(dev) (dev)->dev_name

View File

@ -47,12 +47,6 @@
readl((m)->mbase + ((m)->hbm_mc ? 0xef8 : \
(res_cfg->type == GNR ? 0xaf8 : 0x20ef8)) + \
(i) * (m)->chan_mmio_sz)
#define I10NM_GET_REG32(m, i, offset) \
readl((m)->mbase + (i) * (m)->chan_mmio_sz + (offset))
#define I10NM_GET_REG64(m, i, offset) \
readq((m)->mbase + (i) * (m)->chan_mmio_sz + (offset))
#define I10NM_SET_REG32(m, i, offset, v) \
writel(v, (m)->mbase + (i) * (m)->chan_mmio_sz + (offset))
#define I10NM_GET_SCK_MMIO_BASE(reg) (GET_BITFIELD(reg, 0, 28) << 23)
#define I10NM_GET_IMC_MMIO_OFFSET(reg) (GET_BITFIELD(reg, 0, 10) << 12)
@ -79,11 +73,12 @@ static struct res_config *res_cfg;
static int retry_rd_err_log;
static int decoding_via_mca;
static bool mem_cfg_2lm;
static bool no_adxl;
static struct reg_rrl icx_reg_rrl_ddr = {
.set_num = 2,
.reg_num = 6,
.modes = {LRE_SCRUB, LRE_DEMAND},
.sources = {RRL_SRC_LRE_SCRUB, RRL_SRC_LRE_DEMAND},
.offsets = {
{0x22c60, 0x22c54, 0x22c5c, 0x22c58, 0x22c28, 0x20ed8},
{0x22e54, 0x22e60, 0x22e64, 0x22e58, 0x22e5c, 0x20ee0},
@ -104,7 +99,7 @@ static struct reg_rrl icx_reg_rrl_ddr = {
static struct reg_rrl spr_reg_rrl_ddr = {
.set_num = 3,
.reg_num = 6,
.modes = {LRE_SCRUB, LRE_DEMAND, FRE_DEMAND},
.sources = {RRL_SRC_LRE_SCRUB, RRL_SRC_LRE_DEMAND, RRL_SRC_FRE_DEMAND},
.offsets = {
{0x22c60, 0x22c54, 0x22f08, 0x22c58, 0x22c28, 0x20ed8},
{0x22e54, 0x22e60, 0x22f10, 0x22e58, 0x22e5c, 0x20ee0},
@ -126,7 +121,7 @@ static struct reg_rrl spr_reg_rrl_ddr = {
static struct reg_rrl spr_reg_rrl_hbm_pch0 = {
.set_num = 2,
.reg_num = 6,
.modes = {LRE_SCRUB, LRE_DEMAND},
.sources = {RRL_SRC_LRE_SCRUB, RRL_SRC_LRE_DEMAND},
.offsets = {
{0x2860, 0x2854, 0x2b08, 0x2858, 0x2828, 0x0ed8},
{0x2a54, 0x2a60, 0x2b10, 0x2a58, 0x2a5c, 0x0ee0},
@ -147,7 +142,7 @@ static struct reg_rrl spr_reg_rrl_hbm_pch0 = {
static struct reg_rrl spr_reg_rrl_hbm_pch1 = {
.set_num = 2,
.reg_num = 6,
.modes = {LRE_SCRUB, LRE_DEMAND},
.sources = {RRL_SRC_LRE_SCRUB, RRL_SRC_LRE_DEMAND},
.offsets = {
{0x2c60, 0x2c54, 0x2f08, 0x2c58, 0x2c28, 0x0fa8},
{0x2e54, 0x2e60, 0x2f10, 0x2e58, 0x2e5c, 0x0fb0},
@ -168,7 +163,7 @@ static struct reg_rrl spr_reg_rrl_hbm_pch1 = {
static struct reg_rrl gnr_reg_rrl_ddr = {
.set_num = 4,
.reg_num = 6,
.modes = {FRE_SCRUB, FRE_DEMAND, LRE_SCRUB, LRE_DEMAND},
.sources = {RRL_SRC_FRE_SCRUB, RRL_SRC_FRE_DEMAND, RRL_SRC_LRE_SCRUB, RRL_SRC_LRE_DEMAND},
.offsets = {
{0x2f10, 0x2f20, 0x2f30, 0x2f50, 0x2f60, 0xba0},
{0x2f14, 0x2f24, 0x2f38, 0x2f54, 0x2f64, 0xba8},
@ -188,214 +183,6 @@ static struct reg_rrl gnr_reg_rrl_ddr = {
.cecnt_widths = {4, 4, 4, 4, 4, 4, 4, 4},
};
static u64 read_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width)
{
switch (width) {
case 4:
return I10NM_GET_REG32(imc, chan, offset);
case 8:
return I10NM_GET_REG64(imc, chan, offset);
default:
i10nm_printk(KERN_ERR, "Invalid read RRL 0x%x width %d\n", offset, width);
return 0;
}
}
static void write_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width, u64 val)
{
switch (width) {
case 4:
return I10NM_SET_REG32(imc, chan, offset, (u32)val);
default:
i10nm_printk(KERN_ERR, "Invalid write RRL 0x%x width %d\n", offset, width);
}
}
static void enable_rrl(struct skx_imc *imc, int chan, struct reg_rrl *rrl,
int rrl_set, bool enable, u32 *rrl_ctl)
{
enum rrl_mode mode = rrl->modes[rrl_set];
u32 offset = rrl->offsets[rrl_set][0], v;
u8 width = rrl->widths[0];
bool first, scrub;
/* First or last read error. */
first = (mode == FRE_SCRUB || mode == FRE_DEMAND);
/* Patrol scrub or on-demand read error. */
scrub = (mode == FRE_SCRUB || mode == LRE_SCRUB);
v = read_imc_reg(imc, chan, offset, width);
if (enable) {
/* Save default configurations. */
*rrl_ctl = v;
v &= ~rrl->uc_mask;
if (first)
v |= rrl->noover_mask;
else
v &= ~rrl->noover_mask;
if (scrub)
v |= rrl->en_patspr_mask;
else
v &= ~rrl->en_patspr_mask;
v |= rrl->en_mask;
} else {
/* Restore default configurations. */
if (*rrl_ctl & rrl->uc_mask)
v |= rrl->uc_mask;
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;
}
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 = res_cfg->reg_rrl_ddr;
int i, chan_num = 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, enable, chan[i].rrl_ctl[0]);
}
static void enable_rrls_hbm(struct skx_imc *imc, bool enable)
{
struct reg_rrl **rrl_hbm = res_cfg->reg_rrl_hbm;
int i, chan_num = 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]);
}
}
static void enable_retry_rd_err_log(bool enable)
{
struct skx_dev *d;
int i, imc_num;
edac_dbg(2, "\n");
list_for_each_entry(d, i10nm_edac_list, list) {
imc_num = res_cfg->ddr_imc_num;
for (i = 0; i < imc_num; i++)
enable_rrls_ddr(&d->imc[i], enable);
imc_num += res_cfg->hbm_imc_num;
for (; i < imc_num; i++)
enable_rrls_hbm(&d->imc[i], enable);
}
}
static void show_retry_rd_err_log(struct decoded_addr *res, char *msg,
int len, bool scrub_err)
{
int i, j, n, ch = res->channel, pch = res->cs & 1;
struct skx_imc *imc = &res->dev->imc[res->imc];
u64 log, corr, status_mask;
struct reg_rrl *rrl;
bool scrub;
u32 offset;
u8 width;
if (!imc->mbase)
return;
rrl = imc->hbm_mc ? res_cfg->reg_rrl_hbm[pch] : res_cfg->reg_rrl_ddr;
if (!rrl)
return;
status_mask = rrl->over_mask | rrl->uc_mask | rrl->v_mask;
n = scnprintf(msg, len, " retry_rd_err_log[");
for (i = 0; i < rrl->set_num; i++) {
scrub = (rrl->modes[i] == FRE_SCRUB || rrl->modes[i] == LRE_SCRUB);
if (scrub_err != scrub)
continue;
for (j = 0; j < rrl->reg_num && len - n > 0; j++) {
offset = rrl->offsets[i][j];
width = rrl->widths[j];
log = read_imc_reg(imc, ch, offset, width);
if (width == 4)
n += scnprintf(msg + n, len - n, "%.8llx ", log);
else
n += scnprintf(msg + n, len - n, "%.16llx ", log);
/* Clear RRL status if RRL in Linux control mode. */
if (retry_rd_err_log == 2 && !j && (log & status_mask))
write_imc_reg(imc, ch, offset, width, log & ~status_mask);
}
}
/* Move back one space. */
n--;
n += scnprintf(msg + n, len - n, "]");
if (len - n > 0) {
n += scnprintf(msg + n, len - n, " correrrcnt[");
for (i = 0; i < rrl->cecnt_num && len - n > 0; i++) {
offset = rrl->cecnt_offsets[i];
width = rrl->cecnt_widths[i];
corr = read_imc_reg(imc, ch, offset, width);
/* CPUs {ICX,SPR} encode two counters per 4-byte CORRERRCNT register. */
if (res_cfg->type <= SPR) {
n += scnprintf(msg + n, len - n, "%.4llx %.4llx ",
corr & 0xffff, corr >> 16);
} else {
/* CPUs {GNR} encode one counter per CORRERRCNT register. */
if (width == 4)
n += scnprintf(msg + n, len - n, "%.8llx ", corr);
else
n += scnprintf(msg + n, len - n, "%.16llx ", corr);
}
}
/* Move back one space. */
n--;
n += scnprintf(msg + n, len - n, "]");
}
}
static struct pci_dev *pci_get_dev_wrapper(int dom, unsigned int bus,
unsigned int dev, unsigned int fun)
{
@ -980,7 +767,7 @@ static struct res_config i10nm_cfg0 = {
.ddr_mdev_bdf = {0, 12, 0},
.hbm_mdev_bdf = {0, 12, 1},
.sad_all_offset = 0x108,
.reg_rrl_ddr = &icx_reg_rrl_ddr,
.reg_rrl_ddr[0] = &icx_reg_rrl_ddr,
};
static struct res_config i10nm_cfg1 = {
@ -998,7 +785,7 @@ static struct res_config i10nm_cfg1 = {
.ddr_mdev_bdf = {0, 12, 0},
.hbm_mdev_bdf = {0, 12, 1},
.sad_all_offset = 0x108,
.reg_rrl_ddr = &icx_reg_rrl_ddr,
.reg_rrl_ddr[0] = &icx_reg_rrl_ddr,
};
static struct res_config spr_cfg = {
@ -1021,7 +808,7 @@ static struct res_config spr_cfg = {
.ddr_mdev_bdf = {0, 12, 0},
.hbm_mdev_bdf = {0, 12, 1},
.sad_all_offset = 0x300,
.reg_rrl_ddr = &spr_reg_rrl_ddr,
.reg_rrl_ddr[0] = &spr_reg_rrl_ddr,
.reg_rrl_hbm[0] = &spr_reg_rrl_hbm_pch0,
.reg_rrl_hbm[1] = &spr_reg_rrl_hbm_pch1,
};
@ -1041,7 +828,7 @@ static struct res_config gnr_cfg = {
.uracu_bdf = {0, 0, 1},
.ddr_mdev_bdf = {0, 5, 1},
.sad_all_offset = 0x300,
.reg_rrl_ddr = &gnr_reg_rrl_ddr,
.reg_rrl_ddr[0] = &gnr_reg_rrl_ddr,
};
static const struct x86_cpu_id i10nm_cpuids[] = {
@ -1222,21 +1009,28 @@ static int __init i10nm_init(void)
}
rc = skx_adxl_get();
if (rc)
goto fail;
if (rc) {
/* Decoding errors via MCA banks for 2LM isn't supported yet */
if (rc != -ENODEV || mem_cfg_2lm)
goto fail;
i10nm_printk(KERN_INFO, "ADXL not found, falling back to MCA-based decoding.\n");
no_adxl = true;
decoding_via_mca = true;
}
opstate_init();
mce_register_decode_chain(&i10nm_mce_dec);
skx_setup_debug("i10nm_test");
if (retry_rd_err_log && res_cfg->reg_rrl_ddr) {
skx_set_decode(i10nm_mc_decode, show_retry_rd_err_log);
if (retry_rd_err_log == 2)
enable_retry_rd_err_log(true);
} else {
skx_set_decode(i10nm_mc_decode, NULL);
res_cfg->rrl_ctrl_mode = retry_rd_err_log;
if (retry_rd_err_log && res_cfg->reg_rrl_ddr[0]) {
skx_set_show_rrl(skx_show_rrl);
if (retry_rd_err_log == RRL_CTRL_LINUX)
skx_enable_rrl(true);
}
skx_set_decode(i10nm_mc_decode);
i10nm_printk(KERN_INFO, "%s\n", I10NM_REVISION);
return 0;
@ -1249,15 +1043,18 @@ static void __exit i10nm_exit(void)
{
edac_dbg(2, "\n");
if (retry_rd_err_log && res_cfg->reg_rrl_ddr) {
skx_set_decode(NULL, NULL);
if (retry_rd_err_log == 2)
enable_retry_rd_err_log(false);
skx_set_decode(NULL);
if (retry_rd_err_log && res_cfg->reg_rrl_ddr[0]) {
if (retry_rd_err_log == RRL_CTRL_LINUX)
skx_enable_rrl(false);
skx_set_show_rrl(NULL);
}
skx_teardown_debug();
mce_unregister_decode_chain(&i10nm_mce_dec);
skx_adxl_put();
if (!no_adxl)
skx_adxl_put();
skx_remove();
}

View File

@ -485,11 +485,11 @@ static void i3000_remove_one(struct pci_dev *pdev)
static const struct pci_device_id i3000_pci_tbl[] = {
{
PCI_VEND_DEV(INTEL, 3000_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
I3000},
{
0,
} /* 0 terminated list. */
PCI_VEND_DEV(INTEL, 3000_HB),
.driver_data = I3000,
}, {
/* 0 terminated list. */
}
};
MODULE_DEVICE_TABLE(pci, i3000_pci_tbl);

View File

@ -466,11 +466,11 @@ static void i3200_remove_one(struct pci_dev *pdev)
static const struct pci_device_id i3200_pci_tbl[] = {
{
PCI_VEND_DEV(INTEL, 3200_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
I3200},
{
0,
} /* 0 terminated list. */
PCI_VEND_DEV(INTEL, 3200_HB),
.driver_data = I3200,
}, {
/* 0 terminated list. */
}
};
MODULE_DEVICE_TABLE(pci, i3200_pci_tbl);

View File

@ -352,6 +352,9 @@ struct i5000_pvt {
/* Actual values for this controller */
int maxch; /* Max channels */
int maxdimmperch; /* Max DIMMs per channel */
/* Hardware error reporting status */
bool enabled_error_reporting;
};
/* I5000 MCH error information retrieved from Hardware */
@ -1302,10 +1305,10 @@ static int i5000_init_csrows(struct mem_ctl_info *mci)
}
/*
* i5000_enable_error_reporting
* Turn on the memory reporting features of the hardware
* i5000_set_error_reporting
* Turn on/off the memory reporting features of the hardware
*/
static void i5000_enable_error_reporting(struct mem_ctl_info *mci)
static void i5000_set_error_reporting(struct mem_ctl_info *mci, bool enable)
{
struct i5000_pvt *pvt;
u32 fbd_error_mask;
@ -1316,8 +1319,11 @@ static void i5000_enable_error_reporting(struct mem_ctl_info *mci)
pci_read_config_dword(pvt->branchmap_werrors, EMASK_FBD,
&fbd_error_mask);
/* Enable with a '0' */
fbd_error_mask &= ~(ENABLE_EMASK_ALL);
/* Enable with 0, disable with 1 */
if (enable)
fbd_error_mask &= ~(ENABLE_EMASK_ALL);
else
fbd_error_mask |= ENABLE_EMASK_ALL;
pci_write_config_dword(pvt->branchmap_werrors, EMASK_FBD,
fbd_error_mask);
@ -1435,17 +1441,19 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
if (i5000_init_csrows(mci)) {
edac_dbg(0, "MC: Setting mci->edac_cap to EDAC_FLAG_NONE because i5000_init_csrows() returned nonzero value\n");
mci->edac_cap = EDAC_FLAG_NONE; /* no csrows found */
pvt->enabled_error_reporting = false;
} else {
edac_dbg(1, "MC: Enable error reporting now\n");
i5000_enable_error_reporting(mci);
i5000_set_error_reporting(mci, true);
pvt->enabled_error_reporting = true;
}
/* add this new MC control structure to EDAC's list of MCs */
if (edac_mc_add_mc(mci)) {
edac_dbg(0, "MC: failed edac_mc_add_mc()\n");
/* FIXME: perhaps some code should go here that disables error
* reporting if we just enabled it
*/
/* Disable error reporting if we previously enabled it */
if (pvt->enabled_error_reporting)
i5000_set_error_reporting(mci, false);
goto fail1;
}
@ -1503,6 +1511,7 @@ static int i5000_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
static void i5000_remove_one(struct pci_dev *pdev)
{
struct mem_ctl_info *mci;
struct i5000_pvt *pvt;
edac_dbg(0, "\n");
@ -1512,6 +1521,12 @@ static void i5000_remove_one(struct pci_dev *pdev)
if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return;
pvt = mci->pvt_info;
/* Disable error reporting on teardown */
if (pvt->enabled_error_reporting)
i5000_set_error_reporting(mci, false);
/* retrieve references to resources, and free those resources */
i5000_put_devices(mci);
edac_mc_free(mci);

View File

@ -859,6 +859,21 @@ static void i5100_init_csrows(struct mem_ctl_info *mci)
}
}
static void i5100_set_error_reporting(struct pci_dev *pdev, bool enable)
{
u32 dw;
pci_read_config_dword(pdev, I5100_EMASK_MEM, &dw);
/* Enable with 0, disable with 1 */
if (enable)
dw &= ~I5100_FERR_NF_MEM_ANY_MASK;
else
dw |= I5100_FERR_NF_MEM_ANY_MASK;
pci_write_config_dword(pdev, I5100_EMASK_MEM, dw);
}
/****************************************************************************
* Error injection routines
****************************************************************************/
@ -1004,11 +1019,6 @@ static int i5100_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
pci_read_config_dword(pdev, I5100_MS, &dw);
ranksperch = !!(dw & (1 << 8)) * 2 + 4;
/* enable error reporting... */
pci_read_config_dword(pdev, I5100_EMASK_MEM, &dw);
dw &= ~I5100_FERR_NF_MEM_ANY_MASK;
pci_write_config_dword(pdev, I5100_EMASK_MEM, dw);
/* device 21, func 0, Channel 0 Memory Map, Error Flag/Mask, etc... */
ch0mm = pci_get_device_func(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_5100_21, 0);
@ -1125,6 +1135,9 @@ static int i5100_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
i5100_setup_debugfs(mci);
/* Enable error reporting on success */
i5100_set_error_reporting(pdev, true);
return ret;
bail_scrub:
@ -1169,6 +1182,9 @@ static void i5100_remove_one(struct pci_dev *pdev)
priv = mci->pvt_info;
/* Disable error reporting at teardown */
i5100_set_error_reporting(pdev, false);
edac_debugfs_remove_recursive(priv->debugfs);
priv->scrub_enable = 0;

View File

@ -353,6 +353,9 @@ struct i5400_pvt {
/* Actual values for this controller */
int maxch; /* Max channels */
int maxdimmperch; /* Max DIMMs per channel */
/* Hardware error reporting status */
bool enabled_error_reporting;
};
/* I5400 MCH error information retrieved from Hardware */
@ -1223,10 +1226,10 @@ static int i5400_init_dimms(struct mem_ctl_info *mci)
}
/*
* i5400_enable_error_reporting
* Turn on the memory reporting features of the hardware
* i5400_set_error_reporting
* Turn on/off the memory reporting features of the hardware
*/
static void i5400_enable_error_reporting(struct mem_ctl_info *mci)
static void i5400_set_error_reporting(struct mem_ctl_info *mci, bool enable)
{
struct i5400_pvt *pvt;
u32 fbd_error_mask;
@ -1237,8 +1240,11 @@ static void i5400_enable_error_reporting(struct mem_ctl_info *mci)
pci_read_config_dword(pvt->branchmap_werrors, EMASK_FBD,
&fbd_error_mask);
/* Enable with a '0' */
fbd_error_mask &= ~(ENABLE_EMASK_ALL);
/* Enable with 0, disable with 1 */
if (enable)
fbd_error_mask &= ~(ENABLE_EMASK_ALL);
else
fbd_error_mask |= ENABLE_EMASK_ALL;
pci_write_config_dword(pvt->branchmap_werrors, EMASK_FBD,
fbd_error_mask);
@ -1319,17 +1325,19 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
if (i5400_init_dimms(mci)) {
edac_dbg(0, "MC: Setting mci->edac_cap to EDAC_FLAG_NONE because i5400_init_dimms() returned nonzero value\n");
mci->edac_cap = EDAC_FLAG_NONE; /* no dimms found */
pvt->enabled_error_reporting = false;
} else {
edac_dbg(1, "MC: Enable error reporting now\n");
i5400_enable_error_reporting(mci);
i5400_set_error_reporting(mci, true);
pvt->enabled_error_reporting = true;
}
/* add this new MC control structure to EDAC's list of MCs */
if (edac_mc_add_mc(mci)) {
edac_dbg(0, "MC: failed edac_mc_add_mc()\n");
/* FIXME: perhaps some code should go here that disables error
* reporting if we just enabled it
*/
/* Disable error reporting if we just enabled it */
if (pvt->enabled_error_reporting)
i5400_set_error_reporting(mci, false);
goto fail1;
}
@ -1387,6 +1395,7 @@ static int i5400_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
static void i5400_remove_one(struct pci_dev *pdev)
{
struct mem_ctl_info *mci;
struct i5400_pvt *pvt;
edac_dbg(0, "\n");
@ -1397,6 +1406,12 @@ static void i5400_remove_one(struct pci_dev *pdev)
if (!mci)
return;
pvt = mci->pvt_info;
/* Disable error reporting on teardown */
if (pvt->enabled_error_reporting)
i5400_set_error_reporting(mci, false);
/* retrieve references to resources, and free those resources */
i5400_put_devices(mci);

View File

@ -111,6 +111,9 @@ struct i7300_pvt {
/* Temporary buffer for use when preparing error messages */
char *tmp_prt_buffer;
/* Hardware error reporting status */
bool enabled_error_reporting;
};
/* FIXME: Why do we need to have this static? */
@ -550,11 +553,12 @@ static void i7300_clear_error(struct mem_ctl_info *mci)
}
/**
* i7300_enable_error_reporting() - Enable the memory reporting logic at the
* i7300_set_error_reporting() - Enable or disable the memory reporting logic at the
* hardware
* @mci: struct mem_ctl_info pointer
* @enable: enables if 'true', disables if 'false'
*/
static void i7300_enable_error_reporting(struct mem_ctl_info *mci)
static void i7300_set_error_reporting(struct mem_ctl_info *mci, bool enable)
{
struct i7300_pvt *pvt = mci->pvt_info;
u32 fbd_error_mask;
@ -563,8 +567,11 @@ static void i7300_enable_error_reporting(struct mem_ctl_info *mci)
pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
EMASK_FBD, &fbd_error_mask);
/* Enable with a '0' */
fbd_error_mask &= ~(EMASK_FBD_ERR_MASK);
/* Enable with 0, disable with 1 */
if (enable)
fbd_error_mask &= ~(EMASK_FBD_ERR_MASK);
else
fbd_error_mask |= EMASK_FBD_ERR_MASK;
pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
EMASK_FBD, fbd_error_mask);
@ -1087,17 +1094,19 @@ static int i7300_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (i7300_get_mc_regs(mci)) {
edac_dbg(0, "MC: Setting mci->edac_cap to EDAC_FLAG_NONE because i7300_init_csrows() returned nonzero value\n");
mci->edac_cap = EDAC_FLAG_NONE; /* no csrows found */
pvt->enabled_error_reporting = false;
} else {
edac_dbg(1, "MC: Enable error reporting now\n");
i7300_enable_error_reporting(mci);
i7300_set_error_reporting(mci, true);
pvt->enabled_error_reporting = true;
}
/* add this new MC control structure to EDAC's list of MCs */
if (edac_mc_add_mc(mci)) {
edac_dbg(0, "MC: failed edac_mc_add_mc()\n");
/* FIXME: perhaps some code should go here that disables error
* reporting if we just enabled it
*/
/* Disable error reporting if we just enabled it */
if (pvt->enabled_error_reporting)
i7300_set_error_reporting(mci, false);
goto fail1;
}
@ -1134,6 +1143,7 @@ static int i7300_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
static void i7300_remove_one(struct pci_dev *pdev)
{
struct mem_ctl_info *mci;
struct i7300_pvt *pvt;
char *tmp;
edac_dbg(0, "\n");
@ -1145,7 +1155,12 @@ static void i7300_remove_one(struct pci_dev *pdev)
if (!mci)
return;
tmp = ((struct i7300_pvt *)mci->pvt_info)->tmp_prt_buffer;
pvt = (struct i7300_pvt *)mci->pvt_info;
tmp = pvt->tmp_prt_buffer;
/* Disable error reporting before unregistering device */
if (pvt->enabled_error_reporting)
i7300_set_error_reporting(mci, false);
/* retrieve references to resources, and free those resources */
i7300_put_devices(mci);

View File

@ -287,11 +287,11 @@ static void i82860_remove_one(struct pci_dev *pdev)
static const struct pci_device_id i82860_pci_tbl[] = {
{
PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
I82860},
{
0,
} /* 0 terminated list. */
PCI_VEND_DEV(INTEL, 82860_0),
.driver_data = I82860,
}, {
/* 0 terminated list. */
}
};
MODULE_DEVICE_TABLE(pci, i82860_pci_tbl);

View File

@ -276,7 +276,7 @@ static int i82875p_setup_overfl_dev(struct pci_dev *pdev,
*ovrfl_pdev = NULL;
*ovrfl_window = NULL;
dev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL);
dev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82875_6, NULL);
if (dev == NULL) {
/* Intel tells BIOS developers to hide device 6 which
@ -518,11 +518,11 @@ static void i82875p_remove_one(struct pci_dev *pdev)
static const struct pci_device_id i82875p_pci_tbl[] = {
{
PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
I82875P},
{
0,
} /* 0 terminated list. */
PCI_VEND_DEV(INTEL, 82875_0),
.driver_data = I82875P,
}, {
/* 0 terminated list. */
}
};
MODULE_DEVICE_TABLE(pci, i82875p_pci_tbl);

View File

@ -624,12 +624,11 @@ static void i82975x_remove_one(struct pci_dev *pdev)
static const struct pci_device_id i82975x_pci_tbl[] = {
{
PCI_VEND_DEV(INTEL, 82975_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
I82975X
},
{
0,
} /* 0 terminated list. */
PCI_VEND_DEV(INTEL, 82975_0),
.driver_data = I82975X
}, {
/* 0 terminated list. */
}
};
MODULE_DEVICE_TABLE(pci, i82975x_pci_tbl);

View File

@ -733,49 +733,49 @@ static struct res_config rpl_s_cfg = {
};
static const struct pci_device_id ie31200_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_1), (kernel_ulong_t)&snb_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_2), (kernel_ulong_t)&snb_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_3), (kernel_ulong_t)&snb_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_4), (kernel_ulong_t)&snb_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_5), (kernel_ulong_t)&snb_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_6), (kernel_ulong_t)&snb_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_7), (kernel_ulong_t)&snb_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_8), (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_9), (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_10), (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_11), (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_12), (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_1), (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_2), (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_3), (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_4), (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_5), (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_6), (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_7), (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_8), (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_9), (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_10), (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_1), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_2), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_3), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_4), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_5), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_6), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_HX_1), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_ADL_S_1), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_ADL_S_2), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_ADL_S_3), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_1), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_2), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_3), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_4), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_5), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_6), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_7), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_8), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_9), (kernel_ulong_t)&rpl_s_cfg},
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_10), (kernel_ulong_t)&rpl_s_cfg},
{ 0, } /* 0 terminated list. */
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_1), .driver_data = (kernel_ulong_t)&snb_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_2), .driver_data = (kernel_ulong_t)&snb_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_3), .driver_data = (kernel_ulong_t)&snb_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_4), .driver_data = (kernel_ulong_t)&snb_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_5), .driver_data = (kernel_ulong_t)&snb_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_6), .driver_data = (kernel_ulong_t)&snb_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_7), .driver_data = (kernel_ulong_t)&snb_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_8), .driver_data = (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_9), .driver_data = (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_10), .driver_data = (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_11), .driver_data = (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_12), .driver_data = (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_1), .driver_data = (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_2), .driver_data = (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_3), .driver_data = (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_4), .driver_data = (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_5), .driver_data = (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_6), .driver_data = (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_7), .driver_data = (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_8), .driver_data = (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_9), .driver_data = (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_10), .driver_data = (kernel_ulong_t)&skl_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_1), .driver_data = (kernel_ulong_t)&rpl_s_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_2), .driver_data = (kernel_ulong_t)&rpl_s_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_3), .driver_data = (kernel_ulong_t)&rpl_s_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_4), .driver_data = (kernel_ulong_t)&rpl_s_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_5), .driver_data = (kernel_ulong_t)&rpl_s_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_S_6), .driver_data = (kernel_ulong_t)&rpl_s_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_RPL_HX_1), .driver_data = (kernel_ulong_t)&rpl_s_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_ADL_S_1), .driver_data = (kernel_ulong_t)&rpl_s_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_ADL_S_2), .driver_data = (kernel_ulong_t)&rpl_s_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_ADL_S_3), .driver_data = (kernel_ulong_t)&rpl_s_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_1), .driver_data = (kernel_ulong_t)&rpl_s_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_2), .driver_data = (kernel_ulong_t)&rpl_s_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_3), .driver_data = (kernel_ulong_t)&rpl_s_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_4), .driver_data = (kernel_ulong_t)&rpl_s_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_5), .driver_data = (kernel_ulong_t)&rpl_s_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_6), .driver_data = (kernel_ulong_t)&rpl_s_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_7), .driver_data = (kernel_ulong_t)&rpl_s_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_8), .driver_data = (kernel_ulong_t)&rpl_s_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_9), .driver_data = (kernel_ulong_t)&rpl_s_cfg },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IE31200_BTL_S_10), .driver_data = (kernel_ulong_t)&rpl_s_cfg },
{ } /* 0 terminated list. */
};
MODULE_DEVICE_TABLE(pci, ie31200_pci_tbl);

View File

@ -122,33 +122,6 @@
#define MEM_SLICE_HASH_MASK(v) (GET_BITFIELD(v, 6, 19) << 6)
#define MEM_SLICE_HASH_LSB_MASK_BIT(v) GET_BITFIELD(v, 24, 26)
static struct res_config {
bool machine_check;
/* The number of present memory controllers. */
int num_imc;
/* Host MMIO configuration */
u64 reg_mchbar_mask;
/* Top of memory */
u64 reg_tom_mask;
/* Top of upper usable DRAM */
u64 reg_touud_mask;
/* IBECC error log */
u64 reg_eccerrlog_addr_mask;
u32 imc_base;
u32 cmf_base;
u32 cmf_size;
u32 ms_hash_offset;
u32 ibecc_base;
u32 ibecc_error_log_offset;
bool (*ibecc_available)(struct pci_dev *pdev);
/* Extract error address logged in IBECC */
u64 (*err_addr)(u64 ecclog);
/* Convert error address logged in IBECC to system physical address */
u64 (*err_addr_to_sys_addr)(u64 eaddr, int mc);
/* Convert error address logged in IBECC to integrated memory controller address */
u64 (*err_addr_to_imc_addr)(u64 eaddr, int mc);
} *res_cfg;
struct igen6_imc {
int mc;
struct mem_ctl_info *mci;
@ -163,8 +136,56 @@ struct igen6_imc {
int dimm_l_map[NUM_CHANNELS];
};
static struct res_config {
bool machine_check;
/* The number of present memory controllers. */
int num_imc;
/* Host MMIO configuration */
u64 reg_mchbar_mask;
/* Top of memory */
u64 reg_tom_mask;
/* Top of upper usable DRAM */
u64 reg_touud_mask;
/* IBECC error log */
u64 reg_eccerrlog_addr_mask;
/* MEMSS_PMA_CR registers. */
u32 reg_mem_config_offset;
u32 reg_mem_config_ddr_type_mask;
u32 reg_mem_config_ibecc_en_mask;
u32 reg_capabilities_misc_offset;
u32 reg_capabilities_misc_ibecc_dis;
/* Memory controller registers. */
u32 reg_mad_inter_size_mask[NUM_CHANNELS];
u64 reg_mad_inter_size_granularity;
u32 reg_mad_intra_rank_mask[NUM_DIMMS];
u32 reg_mad_intra_width_mask[NUM_DIMMS];
u32 reg_mad_intra_density_mask[NUM_DIMMS];
u32 imc_base;
u32 cmf_base;
u32 cmf_size;
u32 ms_hash_offset;
u32 ibecc_base;
u32 ibecc_error_log_offset;
/* Get memory type. */
enum mem_type (*get_mem_type)(struct igen6_imc *imc);
/* Get DRAM chip type. */
enum dev_type (*get_dev_type)(struct igen6_imc *imc, int chan, int dimm_l);
/* Set imc->ch_{s_size,l_map}. */
void (*set_chan_params)(struct igen6_imc *imc);
/* Set imc->dimm_{l_size,s_size,l_map}[chan]. */
void (*set_dimm_params)(struct igen6_imc *imc, int chan);
bool (*ibecc_available)(struct pci_dev *pdev);
/* Extract error address logged in IBECC */
u64 (*err_addr)(u64 ecclog);
/* Convert error address logged in IBECC to system physical address */
u64 (*err_addr_to_sys_addr)(u64 eaddr, int mc);
/* Convert error address logged in IBECC to integrated memory controller address */
u64 (*err_addr_to_imc_addr)(u64 eaddr, int mc);
} *res_cfg;
static struct igen6_pvt {
struct igen6_imc imc[NUM_IMC];
void __iomem *memss_pma_cr;
u64 ms_hash;
u64 ms_s_size;
int ms_l_map;
@ -291,10 +312,17 @@ static struct work_struct ecclog_work;
#define DID_PTL_H_SKU11 0xb028
#define DID_PTL_H_SKU12 0xb029
#define DID_PTL_H_SKU13 0xb02a
#define DID_PTL_H_SKU14 0xb00a
/* Compute die IDs for Wildcat Lake with IBECC */
#define DID_WCL_SKU1 0xfd00
/* Compute die IDs for Nova Lake-H/HX with IBECC */
#define DID_NVL_H_SKU1 0xd701
#define DID_NVL_H_SKU2 0xd702
#define DID_NVL_H_SKU3 0xd704
#define DID_NVL_H_SKU4 0xd705
static int get_mchbar(struct pci_dev *pdev, u64 *mchbar)
{
union {
@ -386,27 +414,26 @@ static bool mtl_p_ibecc_available(struct pci_dev *pdev)
return !(CAPID_E_IBECC_BIT18 & v);
}
static bool mtl_ps_ibecc_available(struct pci_dev *pdev)
static bool generic_ibecc_available(struct pci_dev *pdev)
{
#define MCHBAR_MEMSS_IBECCDIS 0x13c00
void __iomem *window;
u64 mchbar;
void __iomem *base = igen6_pvt->memss_pma_cr;
bool present;
u32 val;
if (get_mchbar(pdev, &mchbar))
return false;
window = ioremap(mchbar, MCHBAR_SIZE * 2);
if (!window) {
igen6_printk(KERN_ERR, "Failed to ioremap 0x%llx\n", mchbar);
return false;
if (res_cfg->reg_capabilities_misc_offset) {
val = readl(base + res_cfg->reg_capabilities_misc_offset);
present = !(val & res_cfg->reg_capabilities_misc_ibecc_dis);
edac_dbg(2, "capabilities misc reg 0x%x\n", val);
} else if (res_cfg->reg_mem_config_offset) {
val = readl(base + res_cfg->reg_mem_config_offset);
present = !!(val & res_cfg->reg_mem_config_ibecc_en_mask);
edac_dbg(2, "mem config reg 0x%x\n", val);
} else {
igen6_printk(KERN_ERR, "No register for detecting IBECC presence.\n");
present = false;
}
val = readl(window + MCHBAR_MEMSS_IBECCDIS);
iounmap(window);
/* Bit6: 1 - IBECC is disabled, 0 - IBECC isn't disabled */
return !GET_BITFIELD(val, 6, 6);
return present;
}
static u64 mem_addr_to_sys_addr(u64 maddr)
@ -500,6 +527,119 @@ static u64 rpl_p_err_addr(u64 ecclog)
return field_get(res_cfg->reg_eccerrlog_addr_mask, ecclog);
}
static enum mem_type ptl_h_get_mem_type(struct igen6_imc *imc)
{
u32 mtype, val;
val = readl(igen6_pvt->memss_pma_cr + res_cfg->reg_mem_config_offset);
mtype = field_get(res_cfg->reg_mem_config_ddr_type_mask, val);
edac_dbg(2, "mtype %u (reg 0x%x)\n", mtype, val);
switch (mtype) {
case 1:
return MEM_DDR5;
case 2:
return MEM_LPDDR5;
case 3:
return MEM_LPDDR4;
default:
return MEM_UNKNOWN;
}
}
static enum dev_type ptl_h_get_dev_type(struct igen6_imc *imc, int chan, int dimm)
{
u32 width, val;
val = readl(imc->window + MAD_INTRA_CH0_OFFSET + chan * 4);
width = field_get(res_cfg->reg_mad_intra_width_mask[dimm], val);
switch (width) {
case 1:
return DEV_X8;
default:
return DEV_X16;
}
}
static u64 ptl_h_get_chan_size(struct igen6_imc *imc, int chan)
{
u32 val = readl(imc->window + MAD_INTER_CHANNEL_OFFSET);
return field_get(res_cfg->reg_mad_inter_size_mask[chan], val) *
res_cfg->reg_mad_inter_size_granularity;
}
static u64 ptl_h_get_dimm_size(struct igen6_imc *imc, int chan, int dimm)
{
u32 val = readl(imc->window + MAD_INTRA_CH0_OFFSET + chan * 4);
u32 ranks = 1 << field_get(res_cfg->reg_mad_intra_rank_mask[dimm], val);
/* DRAM device density in Gb */
u64 density = field_get(res_cfg->reg_mad_intra_density_mask[dimm], val) * 4;
enum mem_type mtype = ptl_h_get_mem_type(imc);
enum dev_type dtype = ptl_h_get_dev_type(imc, chan, dimm);
u64 sub_ch_width, dev_num;
switch (mtype) {
case MEM_DDR5:
sub_ch_width = 32;
break;
case MEM_LPDDR5:
case MEM_LPDDR4:
sub_ch_width = 16;
break;
default:
sub_ch_width = 0;
}
switch (dtype) {
case DEV_X8:
dev_num = sub_ch_width / 8;
break;
case DEV_X16:
dev_num = sub_ch_width / 16;
break;
default:
dev_num = 0;
}
edac_dbg(2, "ranks %d, density %lluGb, sub_ch_width %llu, dev_num %llu (reg 0x%x)\n", ranks, density, sub_ch_width, dev_num, val);
return ((dev_num * density / 8) * ranks) << 30;
}
static void ptl_h_set_chan_params(struct igen6_imc *imc)
{
u64 ch0_size = ptl_h_get_chan_size(imc, 0);
u64 ch1_size = ptl_h_get_chan_size(imc, 1);
if (ch0_size <= ch1_size) {
imc->ch_s_size = ch0_size;
imc->ch_l_map = 1;
} else {
imc->ch_s_size = ch1_size;
imc->ch_l_map = 0;
}
}
static void ptl_h_set_dimm_params(struct igen6_imc *imc, int chan)
{
u64 dimm0_size = ptl_h_get_dimm_size(imc, chan, 0);
u64 dimm1_size = ptl_h_get_dimm_size(imc, chan, 1);
if (dimm0_size <= dimm1_size) {
imc->dimm_s_size[chan] = dimm0_size;
imc->dimm_l_size[chan] = dimm1_size;
imc->dimm_l_map[chan] = 1;
} else {
imc->dimm_s_size[chan] = dimm1_size;
imc->dimm_l_size[chan] = dimm0_size;
imc->dimm_l_map[chan] = 0;
}
}
static struct res_config ehl_cfg = {
.num_imc = 1,
.reg_mchbar_mask = GENMASK_ULL(38, 16),
@ -593,18 +733,20 @@ static struct res_config rpl_p_cfg = {
};
static struct res_config mtl_ps_cfg = {
.machine_check = true,
.num_imc = 2,
.reg_mchbar_mask = GENMASK_ULL(41, 17),
.reg_tom_mask = GENMASK_ULL(41, 20),
.reg_touud_mask = GENMASK_ULL(41, 20),
.reg_eccerrlog_addr_mask = GENMASK_ULL(38, 5),
.imc_base = 0xd800,
.ibecc_base = 0xd400,
.ibecc_error_log_offset = 0x170,
.ibecc_available = mtl_ps_ibecc_available,
.err_addr_to_sys_addr = adl_err_addr_to_sys_addr,
.err_addr_to_imc_addr = adl_err_addr_to_imc_addr,
.machine_check = true,
.num_imc = 2,
.reg_mchbar_mask = GENMASK_ULL(41, 17),
.reg_tom_mask = GENMASK_ULL(41, 20),
.reg_touud_mask = GENMASK_ULL(41, 20),
.reg_eccerrlog_addr_mask = GENMASK_ULL(38, 5),
.reg_capabilities_misc_offset = 0x13c00,
.reg_capabilities_misc_ibecc_dis = BIT(6),
.imc_base = 0xd800,
.ibecc_base = 0xd400,
.ibecc_error_log_offset = 0x170,
.ibecc_available = generic_ibecc_available,
.err_addr_to_sys_addr = adl_err_addr_to_sys_addr,
.err_addr_to_imc_addr = adl_err_addr_to_imc_addr,
};
static struct res_config mtl_p_cfg = {
@ -622,6 +764,36 @@ static struct res_config mtl_p_cfg = {
.err_addr_to_imc_addr = adl_err_addr_to_imc_addr,
};
static struct res_config ptl_h_cfg = {
.machine_check = true,
.num_imc = 2,
.reg_mchbar_mask = GENMASK_ULL(41, 17),
.reg_tom_mask = GENMASK_ULL(41, 20),
.reg_touud_mask = GENMASK_ULL(41, 20),
.reg_eccerrlog_addr_mask = GENMASK_ULL(38, 5),
.reg_mem_config_offset = 0x13d04,
.reg_mem_config_ddr_type_mask = GENMASK(8, 6),
.reg_mad_inter_size_mask[0] = GENMASK(15, 8),
.reg_mad_inter_size_mask[1] = GENMASK(23, 16),
.reg_mad_inter_size_granularity = BIT_ULL(29),
.reg_mad_intra_rank_mask[0] = BIT(7),
.reg_mad_intra_rank_mask[1] = BIT(15),
.reg_mad_intra_width_mask[0] = BIT(6),
.reg_mad_intra_width_mask[1] = BIT(14),
.reg_mad_intra_density_mask[0] = GENMASK(3, 0),
.reg_mad_intra_density_mask[1] = GENMASK(11, 8),
.imc_base = 0xd800,
.ibecc_base = 0xd400,
.ibecc_error_log_offset = 0x170,
.get_mem_type = ptl_h_get_mem_type,
.get_dev_type = ptl_h_get_dev_type,
.set_chan_params = ptl_h_set_chan_params,
.set_dimm_params = ptl_h_set_dimm_params,
.ibecc_available = mtl_p_ibecc_available,
.err_addr_to_sys_addr = adl_err_addr_to_sys_addr,
.err_addr_to_imc_addr = adl_err_addr_to_imc_addr,
};
static struct res_config wcl_cfg = {
.machine_check = true,
.num_imc = 1,
@ -637,98 +809,122 @@ static struct res_config wcl_cfg = {
.err_addr_to_imc_addr = adl_err_addr_to_imc_addr,
};
static struct res_config nvl_h_cfg = {
.machine_check = true,
.num_imc = 2,
.reg_mchbar_mask = GENMASK_ULL(41, 17),
.reg_tom_mask = GENMASK_ULL(41, 20),
.reg_touud_mask = GENMASK_ULL(41, 20),
.reg_eccerrlog_addr_mask = GENMASK_ULL(38, 5),
.reg_mem_config_offset = 0x12904,
.reg_mem_config_ddr_type_mask = GENMASK(8, 6),
.reg_mem_config_ibecc_en_mask = GENMASK(3, 2),
.reg_mad_inter_size_mask[0] = GENMASK(15, 8),
.reg_mad_inter_size_mask[1] = GENMASK(23, 16),
.reg_mad_inter_size_granularity = BIT_ULL(29),
.reg_mad_intra_rank_mask[0] = BIT(7),
.reg_mad_intra_rank_mask[1] = BIT(15),
.reg_mad_intra_width_mask[0] = BIT(6),
.reg_mad_intra_width_mask[1] = BIT(14),
.reg_mad_intra_density_mask[0] = GENMASK(3, 0),
.reg_mad_intra_density_mask[1] = GENMASK(11, 8),
.imc_base = 0xd800,
.ibecc_base = 0xd400,
.ibecc_error_log_offset = 0x170,
.get_mem_type = ptl_h_get_mem_type,
.get_dev_type = ptl_h_get_dev_type,
.set_chan_params = ptl_h_set_chan_params,
.set_dimm_params = ptl_h_set_dimm_params,
.ibecc_available = generic_ibecc_available,
.err_addr_to_sys_addr = adl_err_addr_to_sys_addr,
.err_addr_to_imc_addr = adl_err_addr_to_imc_addr,
};
static struct pci_device_id igen6_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, DID_EHL_SKU5), (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU6), (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU7), (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU8), (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU9), (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU10), (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU11), (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU12), (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU13), (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU14), (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU15), (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_ICL_SKU8), (kernel_ulong_t)&icl_cfg },
{ PCI_VDEVICE(INTEL, DID_ICL_SKU10), (kernel_ulong_t)&icl_cfg },
{ PCI_VDEVICE(INTEL, DID_ICL_SKU11), (kernel_ulong_t)&icl_cfg },
{ PCI_VDEVICE(INTEL, DID_ICL_SKU12), (kernel_ulong_t)&icl_cfg },
{ PCI_VDEVICE(INTEL, DID_TGL_SKU), (kernel_ulong_t)&tgl_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_SKU1), (kernel_ulong_t)&adl_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_SKU2), (kernel_ulong_t)&adl_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_SKU3), (kernel_ulong_t)&adl_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_SKU4), (kernel_ulong_t)&adl_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU1), (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU2), (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU3), (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU4), (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU5), (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU6), (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU7), (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU8), (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU9), (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU10), (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU11), (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU12), (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_AZB_SKU1), (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ASL_SKU1), (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ASL_SKU2), (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ASL_SKU3), (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_RPL_P_SKU1), (kernel_ulong_t)&rpl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_RPL_P_SKU2), (kernel_ulong_t)&rpl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_RPL_P_SKU3), (kernel_ulong_t)&rpl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_RPL_P_SKU4), (kernel_ulong_t)&rpl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_RPL_P_SKU5), (kernel_ulong_t)&rpl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_MTL_PS_SKU1), (kernel_ulong_t)&mtl_ps_cfg },
{ PCI_VDEVICE(INTEL, DID_MTL_PS_SKU2), (kernel_ulong_t)&mtl_ps_cfg },
{ PCI_VDEVICE(INTEL, DID_MTL_PS_SKU3), (kernel_ulong_t)&mtl_ps_cfg },
{ PCI_VDEVICE(INTEL, DID_MTL_PS_SKU4), (kernel_ulong_t)&mtl_ps_cfg },
{ PCI_VDEVICE(INTEL, DID_MTL_P_SKU1), (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_MTL_P_SKU2), (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_MTL_P_SKU3), (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_ARL_UH_SKU1), (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_ARL_UH_SKU2), (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_ARL_UH_SKU3), (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU1), (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU2), (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU3), (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU4), (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU5), (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU6), (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU7), (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU8), (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU9), (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU10), (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU11), (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU12), (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU13), (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_WCL_SKU1), (kernel_ulong_t)&wcl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU5), .driver_data = (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU6), .driver_data = (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU7), .driver_data = (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU8), .driver_data = (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU9), .driver_data = (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU10), .driver_data = (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU11), .driver_data = (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU12), .driver_data = (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU13), .driver_data = (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU14), .driver_data = (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_EHL_SKU15), .driver_data = (kernel_ulong_t)&ehl_cfg },
{ PCI_VDEVICE(INTEL, DID_ICL_SKU8), .driver_data = (kernel_ulong_t)&icl_cfg },
{ PCI_VDEVICE(INTEL, DID_ICL_SKU10), .driver_data = (kernel_ulong_t)&icl_cfg },
{ PCI_VDEVICE(INTEL, DID_ICL_SKU11), .driver_data = (kernel_ulong_t)&icl_cfg },
{ PCI_VDEVICE(INTEL, DID_ICL_SKU12), .driver_data = (kernel_ulong_t)&icl_cfg },
{ PCI_VDEVICE(INTEL, DID_TGL_SKU), .driver_data = (kernel_ulong_t)&tgl_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_SKU1), .driver_data = (kernel_ulong_t)&adl_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_SKU2), .driver_data = (kernel_ulong_t)&adl_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_SKU3), .driver_data = (kernel_ulong_t)&adl_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_SKU4), .driver_data = (kernel_ulong_t)&adl_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU1), .driver_data = (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU2), .driver_data = (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU3), .driver_data = (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU4), .driver_data = (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU5), .driver_data = (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU6), .driver_data = (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU7), .driver_data = (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU8), .driver_data = (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU9), .driver_data = (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU10), .driver_data = (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU11), .driver_data = (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ADL_N_SKU12), .driver_data = (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_AZB_SKU1), .driver_data = (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ASL_SKU1), .driver_data = (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ASL_SKU2), .driver_data = (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_ASL_SKU3), .driver_data = (kernel_ulong_t)&adl_n_cfg },
{ PCI_VDEVICE(INTEL, DID_RPL_P_SKU1), .driver_data = (kernel_ulong_t)&rpl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_RPL_P_SKU2), .driver_data = (kernel_ulong_t)&rpl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_RPL_P_SKU3), .driver_data = (kernel_ulong_t)&rpl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_RPL_P_SKU4), .driver_data = (kernel_ulong_t)&rpl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_RPL_P_SKU5), .driver_data = (kernel_ulong_t)&rpl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_MTL_PS_SKU1), .driver_data = (kernel_ulong_t)&mtl_ps_cfg },
{ PCI_VDEVICE(INTEL, DID_MTL_PS_SKU2), .driver_data = (kernel_ulong_t)&mtl_ps_cfg },
{ PCI_VDEVICE(INTEL, DID_MTL_PS_SKU3), .driver_data = (kernel_ulong_t)&mtl_ps_cfg },
{ PCI_VDEVICE(INTEL, DID_MTL_PS_SKU4), .driver_data = (kernel_ulong_t)&mtl_ps_cfg },
{ PCI_VDEVICE(INTEL, DID_MTL_P_SKU1), .driver_data = (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_MTL_P_SKU2), .driver_data = (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_MTL_P_SKU3), .driver_data = (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_ARL_UH_SKU1), .driver_data = (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_ARL_UH_SKU2), .driver_data = (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_ARL_UH_SKU3), .driver_data = (kernel_ulong_t)&mtl_p_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU1), .driver_data = (kernel_ulong_t)&ptl_h_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU2), .driver_data = (kernel_ulong_t)&ptl_h_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU3), .driver_data = (kernel_ulong_t)&ptl_h_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU4), .driver_data = (kernel_ulong_t)&ptl_h_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU5), .driver_data = (kernel_ulong_t)&ptl_h_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU6), .driver_data = (kernel_ulong_t)&ptl_h_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU7), .driver_data = (kernel_ulong_t)&ptl_h_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU8), .driver_data = (kernel_ulong_t)&ptl_h_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU9), .driver_data = (kernel_ulong_t)&ptl_h_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU10), .driver_data = (kernel_ulong_t)&ptl_h_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU11), .driver_data = (kernel_ulong_t)&ptl_h_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU12), .driver_data = (kernel_ulong_t)&ptl_h_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU13), .driver_data = (kernel_ulong_t)&ptl_h_cfg },
{ PCI_VDEVICE(INTEL, DID_PTL_H_SKU14), .driver_data = (kernel_ulong_t)&ptl_h_cfg },
{ PCI_VDEVICE(INTEL, DID_WCL_SKU1), .driver_data = (kernel_ulong_t)&wcl_cfg },
{ PCI_VDEVICE(INTEL, DID_NVL_H_SKU1), .driver_data = (kernel_ulong_t)&nvl_h_cfg },
{ PCI_VDEVICE(INTEL, DID_NVL_H_SKU2), .driver_data = (kernel_ulong_t)&nvl_h_cfg },
{ PCI_VDEVICE(INTEL, DID_NVL_H_SKU3), .driver_data = (kernel_ulong_t)&nvl_h_cfg },
{ PCI_VDEVICE(INTEL, DID_NVL_H_SKU4), .driver_data = (kernel_ulong_t)&nvl_h_cfg },
{ },
};
MODULE_DEVICE_TABLE(pci, igen6_pci_tbl);
static enum dev_type get_width(int dimm_l, u32 mad_dimm)
static enum mem_type get_mem_type(struct igen6_imc *imc)
{
u32 w = dimm_l ? MAD_DIMM_CH_DLW(mad_dimm) :
MAD_DIMM_CH_DSW(mad_dimm);
u32 val;
switch (w) {
case 0:
return DEV_X8;
case 1:
return DEV_X16;
case 2:
return DEV_X32;
default:
return DEV_UNKNOWN;
}
}
if (res_cfg->get_mem_type)
return res_cfg->get_mem_type(imc);
static enum mem_type get_memory_type(u32 mad_inter)
{
u32 t = MAD_INTER_CHANNEL_DDR_TYPE(mad_inter);
val = readl(imc->window + MAD_INTER_CHANNEL_OFFSET);
switch (t) {
switch (MAD_INTER_CHANNEL_DDR_TYPE(val)) {
case 0:
return MEM_DDR4;
case 1:
@ -744,6 +940,73 @@ static enum mem_type get_memory_type(u32 mad_inter)
}
}
static bool large_dimm(struct igen6_imc *imc, int chan, int dimm)
{
return dimm == imc->dimm_l_map[chan];
}
static enum dev_type get_dev_type(struct igen6_imc *imc, int chan, int dimm)
{
u32 width, val;
if (res_cfg->get_dev_type)
return res_cfg->get_dev_type(imc, chan, dimm);
val = readl(imc->window + MAD_DIMM_CH0_OFFSET + chan * 4);
width = large_dimm(imc, chan, dimm) ? MAD_DIMM_CH_DLW(val) :
MAD_DIMM_CH_DSW(val);
switch (width) {
case 0:
return DEV_X8;
case 1:
return DEV_X16;
case 2:
return DEV_X32;
default:
return DEV_UNKNOWN;
}
}
static u64 get_dimm_size(struct igen6_imc *imc, int chan, int dimm)
{
if (large_dimm(imc, chan, dimm))
return imc->dimm_l_size[chan];
return imc->dimm_s_size[chan];
}
static void set_chan_params(struct igen6_imc *imc)
{
u32 val;
if (res_cfg->set_chan_params) {
res_cfg->set_chan_params(imc);
return;
}
val = readl(imc->window + MAD_INTER_CHANNEL_OFFSET);
imc->ch_s_size = MAD_INTER_CHANNEL_CH_S_SIZE(val);
imc->ch_l_map = MAD_INTER_CHANNEL_CH_L_MAP(val);
}
static void set_dimm_params(struct igen6_imc *imc, int chan)
{
u32 val;
if (res_cfg->set_dimm_params) {
res_cfg->set_dimm_params(imc, chan);
return;
}
val = readl(imc->window + MAD_INTRA_CH0_OFFSET + chan * 4);
imc->dimm_l_map[chan] = MAD_INTRA_CH_DIMM_L_MAP(val);
val = readl(imc->window + MAD_DIMM_CH0_OFFSET + chan * 4);
imc->dimm_l_size[chan] = MAD_DIMM_CH_DIMM_L_SIZE(val);
imc->dimm_s_size[chan] = MAD_DIMM_CH_DIMM_S_SIZE(val);
}
static int decode_chan_idx(u64 addr, u64 mask, int intlv_bit)
{
u64 hash_addr = addr & mask, hash = 0;
@ -1084,7 +1347,6 @@ static bool igen6_check_ecc(struct igen6_imc *imc)
static int igen6_get_dimm_config(struct mem_ctl_info *mci)
{
struct igen6_imc *imc = mci->pvt_info;
u32 mad_inter, mad_intra, mad_dimm;
int i, j, ndimms, mc = imc->mc;
struct dimm_info *dimm;
enum mem_type mtype;
@ -1094,33 +1356,20 @@ static int igen6_get_dimm_config(struct mem_ctl_info *mci)
edac_dbg(2, "\n");
mad_inter = readl(imc->window + MAD_INTER_CHANNEL_OFFSET);
mtype = get_memory_type(mad_inter);
mtype = get_mem_type(imc);
ecc = igen6_check_ecc(imc);
imc->ch_s_size = MAD_INTER_CHANNEL_CH_S_SIZE(mad_inter);
imc->ch_l_map = MAD_INTER_CHANNEL_CH_L_MAP(mad_inter);
set_chan_params(imc);
for (i = 0; i < NUM_CHANNELS; i++) {
mad_intra = readl(imc->window + MAD_INTRA_CH0_OFFSET + i * 4);
mad_dimm = readl(imc->window + MAD_DIMM_CH0_OFFSET + i * 4);
imc->dimm_l_size[i] = MAD_DIMM_CH_DIMM_L_SIZE(mad_dimm);
imc->dimm_s_size[i] = MAD_DIMM_CH_DIMM_S_SIZE(mad_dimm);
imc->dimm_l_map[i] = MAD_INTRA_CH_DIMM_L_MAP(mad_intra);
set_dimm_params(imc, i);
imc->size += imc->dimm_s_size[i];
imc->size += imc->dimm_l_size[i];
ndimms = 0;
for (j = 0; j < NUM_DIMMS; j++) {
dimm = edac_get_dimm(mci, i, j, 0);
if (j ^ imc->dimm_l_map[i]) {
dtype = get_width(0, mad_dimm);
dsize = imc->dimm_s_size[i];
} else {
dtype = get_width(1, mad_dimm);
dsize = imc->dimm_l_size[i];
}
dtype = get_dev_type(imc, i, j);
dsize = get_dimm_size(imc, i, j);
if (!dsize)
continue;
@ -1223,6 +1472,39 @@ static void igen6_debug_setup(void) {}
static void igen6_debug_teardown(void) {}
#endif
static struct igen6_pvt *igen6_pvt_setup(struct pci_dev *pdev)
{
void __iomem *memss_pma_cr;
struct igen6_pvt *pvt;
u64 mchbar;
int rc;
pvt = kzalloc_obj(*igen6_pvt);
if (!pvt)
return NULL;
rc = get_mchbar(pdev, &mchbar);
if (rc) {
kfree(pvt);
return NULL;
}
memss_pma_cr = ioremap(mchbar, MCHBAR_SIZE * 2);
if (!memss_pma_cr) {
kfree(pvt);
return NULL;
}
pvt->memss_pma_cr = memss_pma_cr;
return pvt;
}
static void igen6_pvt_release(struct igen6_pvt *pvt)
{
iounmap(pvt->memss_pma_cr);
kfree(pvt);
}
static int igen6_pci_setup(struct pci_dev *pdev, u64 *mchbar)
{
union {
@ -1296,6 +1578,11 @@ static bool igen6_imc_absent(void __iomem *window)
return readl(window + MAD_INTER_CHANNEL_OFFSET) == ~0;
}
static void imc_release(struct device *dev)
{
/* Nothing to do, the 'imc' owns the 'dev' and will also release it. */
}
static int igen6_register_mci(int mc, void __iomem *window, struct pci_dev *pdev)
{
struct edac_mc_layer layers[2];
@ -1334,6 +1621,7 @@ static int igen6_register_mci(int mc, void __iomem *window, struct pci_dev *pdev
mci->pvt_info = &igen6_pvt->imc[mc];
imc = mci->pvt_info;
imc->dev.release = imc_release;
device_initialize(&imc->dev);
/*
* EDAC core uses mci->pdev(pointer of structure device) as
@ -1549,12 +1837,12 @@ static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
edac_dbg(2, "\n");
igen6_pvt = kzalloc_obj(*igen6_pvt);
res_cfg = (struct res_config *)ent->driver_data;
igen6_pvt = igen6_pvt_setup(pdev);
if (!igen6_pvt)
return -ENOMEM;
res_cfg = (struct res_config *)ent->driver_data;
rc = igen6_pci_setup(pdev, &mchbar);
if (rc)
goto fail;
@ -1603,7 +1891,7 @@ static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
fail2:
igen6_unregister_mcis();
fail:
kfree(igen6_pvt);
igen6_pvt_release(igen6_pvt);
return rc;
}
@ -1618,7 +1906,7 @@ static void igen6_remove(struct pci_dev *pdev)
flush_work(&ecclog_work);
gen_pool_destroy(ecclog_pool);
igen6_unregister_mcis();
kfree(igen6_pvt);
igen6_pvt_release(igen6_pvt);
}
static struct pci_driver igen6_driver = {

View File

@ -71,28 +71,44 @@ struct local_reg {
.width = (cfg)->ip_name##_reg_##reg_name##_width, \
}
static u64 readx(void __iomem *addr, u8 width)
{
switch (width) {
case 1:
return readb(addr);
case 2:
return readw(addr);
case 4:
return readl(addr);
case 8:
return readq(addr);
default:
imh_printk(KERN_ERR, "Invalid reg 0x%p width %d\n", addr, width);
return 0;
}
static struct res_config *res_cfg;
static int retry_rd_err_log;
#define REG_RRL_DEFINE(a0, a1, a2, a3, a4, a5, a6, b0, b1, b2, b3) \
{ \
.set_num = 4, \
.reg_num = 7, \
.sources = {RRL_SRC_FRE_SCRUB, RRL_SRC_FRE_DEMAND, RRL_SRC_LRE_SCRUB, RRL_SRC_LRE_DEMAND}, \
.offsets = { \
{a0, a1, a2, a3, a4, a5, a6}, \
{a0 + 4, a1 + 4, a2 + 8, a3 + 4, a4 + 4, a5 + 8, a6 + 8}, \
{a0 + 8, a1 + 8, a2 + 16, a3 + 8, a4 + 8, a5 + 16, a6 + 16}, \
{a0 + 12, a1 + 12, a2 + 24, a3 + 12, a4 + 12, a5 + 24, a6 + 24}, \
}, \
.widths = {4, 4, 8, 4, 4, 8, 8}, \
.v_mask = BIT(0), \
.uc_mask = BIT(1), \
.over_mask = BIT(2), \
.en_mask = BIT(12), \
.en_patspr_mask = BIT(14), \
.noover_mask = BIT(15), \
.cecnt_num = 4, \
.cecnt_offsets = {b0, b1, b2, b3}, \
.cecnt_widths = {8, 8, 8, 8}, \
}
static struct reg_rrl dmr_reg_rrl_ddr_subch0 = REG_RRL_DEFINE(
0x2dc0, 0x2dd0, 0x2de0, 0x2e00, 0x2e10, 0x2f70, 0x0200,
0x2c10, 0x2c18, 0x2c20, 0x2c28);
static struct reg_rrl dmr_reg_rrl_ddr_subch1 = REG_RRL_DEFINE(
0x6dc0, 0x6dd0, 0x6de0, 0x6e00, 0x6e10, 0x6f70, 0x4200,
0x6c10, 0x6c18, 0x6c20, 0x6c28);
static void __read_local_reg(void *reg)
{
struct local_reg *r = (struct local_reg *)reg;
r->val = readx(r->vbase + r->offset, r->width);
r->val = skx_readx(r->vbase + r->offset, r->width);
}
/* Read a local-view register. */
@ -378,22 +394,16 @@ static bool imh_2lm_enabled(struct res_config *cfg, struct list_head *head)
return false;
}
/* Helpers to read memory controller registers */
static u64 read_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width)
{
return readx(imc->mbase + imc->chan_mmio_sz * chan + offset, width);
}
static u32 read_imc_mcmtr(struct res_config *cfg, struct skx_imc *imc, int chan)
{
return (u32)read_imc_reg(imc, chan, cfg->ddr_reg_mcmtr_offset, cfg->ddr_reg_mcmtr_width);
return (u32)skx_read_imc_reg(imc, chan, cfg->ddr_reg_mcmtr_offset, cfg->ddr_reg_mcmtr_width);
}
static u32 read_imc_dimmmtr(struct res_config *cfg, struct skx_imc *imc, int chan, int dimm)
{
return (u32)read_imc_reg(imc, chan, cfg->ddr_reg_dimmmtr_offset +
cfg->ddr_reg_dimmmtr_width * dimm,
cfg->ddr_reg_dimmmtr_width);
return (u32)skx_read_imc_reg(imc, chan, cfg->ddr_reg_dimmmtr_offset +
cfg->ddr_reg_dimmmtr_width * dimm,
cfg->ddr_reg_dimmmtr_width);
}
static bool ecc_enabled(u32 mcmtr)
@ -503,6 +513,8 @@ static struct res_config dmr_cfg = {
.ha_size = 0x1000,
.ha_reg_mode_offset = 0x4a0,
.ha_reg_mode_width = 4,
.reg_rrl_ddr[0] = &dmr_reg_rrl_ddr_subch0,
.reg_rrl_ddr[1] = &dmr_reg_rrl_ddr_subch1,
};
static const struct x86_cpu_id imh_cpuids[] = {
@ -542,6 +554,7 @@ static int __init imh_init(void)
return -ENODEV;
cfg = (struct res_config *)id->driver_data;
skx_set_res_cfg(cfg);
res_cfg = cfg;
if (!imh_get_tolm_tohm(cfg, &tolm, &tohm))
return -ENODEV;
@ -576,6 +589,13 @@ static int __init imh_init(void)
mce_register_decode_chain(&imh_mce_dec);
skx_setup_debug("imh_test");
cfg->rrl_ctrl_mode = retry_rd_err_log;
if (retry_rd_err_log && cfg->reg_rrl_ddr[0]) {
skx_set_show_rrl(skx_show_rrl);
if (retry_rd_err_log == RRL_CTRL_LINUX)
skx_enable_rrl(true);
}
imh_printk(KERN_INFO, "%s\n", IMH_REVISION);
return 0;
@ -588,6 +608,12 @@ static void __exit imh_exit(void)
{
edac_dbg(2, "\n");
if (retry_rd_err_log && res_cfg->reg_rrl_ddr[0]) {
if (retry_rd_err_log == RRL_CTRL_LINUX)
skx_enable_rrl(false);
skx_set_show_rrl(NULL);
}
skx_teardown_debug();
mce_unregister_decode_chain(&imh_mce_dec);
skx_adxl_put();
@ -597,6 +623,9 @@ static void __exit imh_exit(void)
module_init(imh_init);
module_exit(imh_exit);
module_param(retry_rd_err_log, int, 0444);
MODULE_PARM_DESC(retry_rd_err_log, "retry_rd_err_log: 0=off(default), 1=bios(Linux doesn't reset any control bits, but just reports values.), 2=linux(Linux tries to take control and resets mode bits, clear valid/UC bits after reading.)");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Qiuxu Zhuo");
MODULE_DESCRIPTION("MC Driver for Intel servers using IMH-based memory controller");

View File

@ -2016,7 +2016,7 @@ static bool sb_decode_ddr4(struct mem_ctl_info *mci, int ch, u8 rank,
static bool sb_decode_ddr3(struct mem_ctl_info *mci, int ch, u8 rank,
u64 rank_addr, char *msg)
{
pr_warn_once("DDR3 row/column decode not support yet!\n");
pr_warn_once("DDR3 row/column decode is not supported yet!\n");
msg[0] = '\0';
return false;
}

View File

@ -671,14 +671,14 @@ static int __init skx_init(void)
}
}
skx_set_decode(skx_decode, skx_show_retry_rd_err_log);
skx_set_show_rrl(skx_show_retry_rd_err_log);
if (nvdimm_count && skx_adxl_get() != -ENODEV) {
skx_set_decode(NULL, skx_show_retry_rd_err_log);
skx_set_decode(NULL);
} else {
if (nvdimm_count)
skx_printk(KERN_NOTICE, "Only decoding DDR4 address!\n");
skx_set_decode(skx_decode, skx_show_retry_rd_err_log);
skx_set_decode(skx_decode);
}
/* Ensure that the OPSTATE is set correctly for POLL or NMI */

View File

@ -31,10 +31,12 @@ static const char * const component_names[] = {
[INDEX_CHANNEL] = "ChannelId",
[INDEX_DIMM] = "DimmSlotId",
[INDEX_CS] = "ChipSelect",
[INDEX_SUBCH] = "SubChId",
[INDEX_NM_MEMCTRL] = "NmMemoryControllerId",
[INDEX_NM_CHANNEL] = "NmChannelId",
[INDEX_NM_DIMM] = "NmDimmSlotId",
[INDEX_NM_CS] = "NmChipSelect",
[INDEX_NM_SUBCH] = "NmSubChId",
};
static int component_indices[ARRAY_SIZE(component_names)];
@ -43,15 +45,284 @@ static const char * const *adxl_component_names;
static u64 *adxl_values;
static char *adxl_msg;
static unsigned long adxl_nm_bitmap;
static unsigned long adxl_bitmap;
static char skx_msg[MSG_SIZE];
static skx_decode_f driver_decode;
static skx_show_retry_log_f skx_show_retry_rd_err_log;
static skx_show_rrl_f show_rrl;
static u64 skx_tolm, skx_tohm;
static LIST_HEAD(dev_edac_list);
static bool skx_mem_cfg_2lm;
static struct res_config *skx_res_cfg;
u64 skx_readx(void __iomem *addr, u8 width)
{
switch (width) {
case 1:
return readb(addr);
case 2:
return readw(addr);
case 4:
return readl(addr);
case 8:
return readq(addr);
default:
skx_printk(KERN_ERR, "Invalid reg 0x%p width %u to read.\n", addr, width);
return 0;
}
}
EXPORT_SYMBOL_GPL(skx_readx);
static void skx_writex(void __iomem *addr, u8 width, u64 val)
{
switch (width) {
case 1:
writeb((u8)val, addr);
return;
case 2:
writew((u16)val, addr);
return;
case 4:
writel((u32)val, addr);
return;
case 8:
writeq(val, addr);
return;
default:
skx_printk(KERN_ERR, "Invalid reg 0x%p width %u to write 0x%llx.\n", addr, width, val);
}
}
u64 skx_read_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width)
{
return skx_readx(imc->mbase + imc->chan_mmio_sz * chan + offset, width);
}
EXPORT_SYMBOL_GPL(skx_read_imc_reg);
void skx_write_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width, u64 val)
{
skx_writex(imc->mbase + imc->chan_mmio_sz * chan + offset, width, val);
}
EXPORT_SYMBOL_GPL(skx_write_imc_reg);
static void enable_rrl(struct skx_imc *imc, int chan, struct reg_rrl *rrl,
int rrl_set, bool enable, u32 *rrl_ctl)
{
enum rrl_source_type source = rrl->sources[rrl_set];
u32 offset = rrl->offsets[rrl_set][0], v;
u8 width = rrl->widths[0];
bool first, scrub;
/* First or last read error. */
first = (source == RRL_SRC_FRE_SCRUB || source == RRL_SRC_FRE_DEMAND);
/* Patrol scrub or on-demand read error. */
scrub = (source == RRL_SRC_FRE_SCRUB || source == RRL_SRC_LRE_SCRUB);
v = skx_read_imc_reg(imc, chan, offset, width);
if (enable) {
/* Save default configurations. */
*rrl_ctl = v;
v &= ~rrl->uc_mask;
if (first)
v |= rrl->noover_mask;
else
v &= ~rrl->noover_mask;
if (scrub)
v |= rrl->en_patspr_mask;
else
v &= ~rrl->en_patspr_mask;
v |= rrl->en_mask;
} else {
/* Restore default configurations. */
if (*rrl_ctl & rrl->uc_mask)
v |= rrl->uc_mask;
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])
return cfg->reg_rrl_ddr[0];
if (res->subch == -1) {
skx_printk(KERN_ERR, "Invalid sub-channel id (-1), possibly missing %s ADXL component.\n", component_names[INDEX_SUBCH]);
return NULL;
}
/* Two groups of RRL sets per DDR channel (e.g., DMR: one group per sub-channel). */
return cfg->reg_rrl_ddr[res->subch & 1];
}
void skx_show_rrl(struct decoded_addr *res, char *msg, int len, bool scrub_err)
{
struct skx_imc *imc = &res->dev->imc[res->imc];
int i, j, n, ch = res->channel;
u64 log, corr, status_mask;
struct reg_rrl *rrl;
bool scrub;
u32 offset;
u8 width;
if (!imc->mbase)
return;
rrl = get_rrl_reg(res, skx_res_cfg);
if (!rrl)
return;
status_mask = rrl->over_mask | rrl->uc_mask | rrl->v_mask;
n = scnprintf(msg, len, " retry_rd_err_log[");
for (i = 0; i < rrl->set_num; i++) {
scrub = (rrl->sources[i] == RRL_SRC_FRE_SCRUB || rrl->sources[i] == RRL_SRC_LRE_SCRUB);
if (scrub_err != scrub)
continue;
for (j = 0; j < rrl->reg_num && len - n > 0; j++) {
offset = rrl->offsets[i][j];
width = rrl->widths[j];
log = skx_read_imc_reg(imc, ch, offset, width);
if (width == 4)
n += scnprintf(msg + n, len - n, "%.8llx ", log);
else
n += scnprintf(msg + n, len - n, "%.16llx ", log);
/* Clear RRL status if RRL in Linux control mode. */
if (skx_res_cfg->rrl_ctrl_mode == RRL_CTRL_LINUX && !j && (log & status_mask))
skx_write_imc_reg(imc, ch, offset, width, log & ~status_mask);
}
}
/* Move back one space. */
n--;
n += scnprintf(msg + n, len - n, "]");
if (len - n > 0) {
n += scnprintf(msg + n, len - n, " correrrcnt[");
for (i = 0; i < rrl->cecnt_num && len - n > 0; i++) {
offset = rrl->cecnt_offsets[i];
width = rrl->cecnt_widths[i];
corr = skx_read_imc_reg(imc, ch, offset, width);
/* CPUs {ICX,SPR} encode two counters per 4-byte CORRERRCNT register. */
if (skx_res_cfg->type <= SPR) {
n += scnprintf(msg + n, len - n, "%.4llx %.4llx ",
corr & 0xffff, corr >> 16);
} else {
/* CPUs {GNR} encode one counter per CORRERRCNT register. */
if (width == 4)
n += scnprintf(msg + n, len - n, "%.8llx ", corr);
else
n += scnprintf(msg + n, len - n, "%.16llx ", corr);
}
}
/* Move back one space. */
n--;
n += scnprintf(msg + n, len - n, "]");
}
}
EXPORT_SYMBOL_GPL(skx_show_rrl);
static bool adxl_component_required(int idx)
{
return idx == INDEX_SOCKET ||
idx == INDEX_MEMCTRL ||
idx == INDEX_CHANNEL ||
idx == INDEX_DIMM ||
idx == INDEX_CS;
}
int skx_adxl_get(void)
{
const char * const *names;
@ -70,12 +341,14 @@ int skx_adxl_get(void)
if (i >= INDEX_NM_FIRST)
adxl_nm_bitmap |= 1 << i;
else
adxl_bitmap |= 1 << i;
break;
}
}
if (!names[j] && i < INDEX_NM_FIRST)
if (!names[j] && adxl_component_required(i))
goto err;
}
@ -202,11 +475,15 @@ static bool skx_adxl_decode(struct decoded_addr *res, enum error_source err_src)
(int)adxl_values[component_indices[INDEX_NM_DIMM]] : -1;
res->cs = (adxl_nm_bitmap & BIT_NM_CS) ?
(int)adxl_values[component_indices[INDEX_NM_CS]] : -1;
res->subch = (adxl_nm_bitmap & BIT_NM_SUBCH) ?
(int)adxl_values[component_indices[INDEX_NM_SUBCH]] : -1;
} else {
res->imc = (int)adxl_values[component_indices[INDEX_MEMCTRL]];
res->channel = (int)adxl_values[component_indices[INDEX_CHANNEL]];
res->dimm = (int)adxl_values[component_indices[INDEX_DIMM]];
res->cs = (int)adxl_values[component_indices[INDEX_CS]];
res->subch = (adxl_bitmap & BIT_SUBCH) ?
(int)adxl_values[component_indices[INDEX_SUBCH]] : -1;
}
if (res->imc < 0) {
@ -262,13 +539,18 @@ void skx_set_res_cfg(struct res_config *cfg)
}
EXPORT_SYMBOL_GPL(skx_set_res_cfg);
void skx_set_decode(skx_decode_f decode, skx_show_retry_log_f show_retry_log)
void skx_set_decode(skx_decode_f decode)
{
driver_decode = decode;
skx_show_retry_rd_err_log = show_retry_log;
}
EXPORT_SYMBOL_GPL(skx_set_decode);
void skx_set_show_rrl(skx_show_rrl_f rrl)
{
show_rrl = rrl;
}
EXPORT_SYMBOL_GPL(skx_set_show_rrl);
static int skx_get_pkg_id(struct skx_dev *d, u8 *id)
{
int node;
@ -466,6 +748,9 @@ int skx_get_dimm_info(u32 mtr, u32 mcmtr, u32 amap, struct dimm_info *dimm,
rows = numrow(mtr);
cols = imc->hbm_mc ? 6 : numcol(mtr);
if (ranks < 0 || rows < 0 || cols < 0)
return 0;
if (imc->hbm_mc) {
banks = 32;
mtype = MEM_HBM2;
@ -714,8 +999,8 @@ static void skx_mce_output_error(struct mem_ctl_info *mci,
res->row, res->column, res->bank_address, res->bank_group);
}
if (skx_show_retry_rd_err_log)
skx_show_retry_rd_err_log(res, skx_msg + len, MSG_SIZE - len, scrub_err);
if (show_rrl)
show_rrl(res, skx_msg + len, MSG_SIZE - len, scrub_err);
edac_dbg(0, "%s\n", skx_msg);

View File

@ -77,27 +77,36 @@
/* Max RRL register sets per {,sub-,pseudo-}channel. */
#define NUM_RRL_SET 4
/* Max RRL registers per set. */
#define NUM_RRL_REG 6
#define NUM_RRL_REG 7
/* Max correctable error count registers. */
#define NUM_CECNT_REG 8
/* Modes of RRL register set. */
enum rrl_mode {
/* Error source from which the RRL registers log errors. */
enum rrl_source_type {
/* Last read error from patrol scrub. */
LRE_SCRUB,
RRL_SRC_LRE_SCRUB,
/* Last read error from demand. */
LRE_DEMAND,
RRL_SRC_LRE_DEMAND,
/* First read error from patrol scrub. */
FRE_SCRUB,
RRL_SRC_FRE_SCRUB,
/* First read error from demand. */
FRE_DEMAND,
RRL_SRC_FRE_DEMAND,
};
enum rrl_ctrl_mode {
/* Linux does not control RRL or reports values. */
RRL_CTRL_NONE,
/* Firmware retains control. Linux only reports values. */
RRL_CTRL_BIOS,
/* Linux takes control, resets mode bits, and clears valid/UC bits; reports values. */
RRL_CTRL_LINUX,
};
/* RRL registers per {,sub-,pseudo-}channel. */
struct reg_rrl {
/* RRL register parts. */
int set_num, reg_num;
enum rrl_mode modes[NUM_RRL_SET];
enum rrl_source_type sources[NUM_RRL_SET];
u32 offsets[NUM_RRL_SET][NUM_RRL_REG];
/* RRL register widths in byte per set. */
u8 widths[NUM_RRL_REG];
@ -201,11 +210,13 @@ enum {
INDEX_CHANNEL,
INDEX_DIMM,
INDEX_CS,
INDEX_SUBCH,
INDEX_NM_FIRST,
INDEX_NM_MEMCTRL = INDEX_NM_FIRST,
INDEX_NM_CHANNEL,
INDEX_NM_DIMM,
INDEX_NM_CS,
INDEX_NM_SUBCH,
INDEX_MAX
};
@ -216,10 +227,12 @@ enum error_source {
ERR_SRC_NOT_MEMORY,
};
#define BIT_SUBCH BIT_ULL(INDEX_SUBCH)
#define BIT_NM_MEMCTRL BIT_ULL(INDEX_NM_MEMCTRL)
#define BIT_NM_CHANNEL BIT_ULL(INDEX_NM_CHANNEL)
#define BIT_NM_DIMM BIT_ULL(INDEX_NM_DIMM)
#define BIT_NM_CS BIT_ULL(INDEX_NM_CS)
#define BIT_NM_SUBCH BIT_ULL(INDEX_NM_SUBCH)
struct decoded_addr {
struct mce *mce;
@ -233,6 +246,7 @@ struct decoded_addr {
int chanways;
int dimm;
int cs;
int subch;
int rank;
int channel_rank;
u64 rank_address;
@ -269,9 +283,11 @@ struct res_config {
int hbm_chan_mmio_sz;
bool support_ddr5;
/* RRL register sets per DDR channel */
struct reg_rrl *reg_rrl_ddr;
struct reg_rrl *reg_rrl_ddr[2];
/* RRL register sets per HBM channel */
struct reg_rrl *reg_rrl_hbm[2];
/* RRL control mode */
enum rrl_ctrl_mode rrl_ctrl_mode;
union {
/* {skx,i10nm}_edac */
struct {
@ -324,11 +340,17 @@ struct res_config {
typedef int (*get_dimm_config_f)(struct mem_ctl_info *mci,
struct res_config *cfg);
typedef bool (*skx_decode_f)(struct decoded_addr *res);
typedef void (*skx_show_retry_log_f)(struct decoded_addr *res, char *msg, int len, bool scrub_err);
typedef void (*skx_show_rrl_f)(struct decoded_addr *res, char *msg, int len, bool scrub_err);
u64 skx_readx(void __iomem *addr, u8 width);
u64 skx_read_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width);
void skx_write_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width, u64 val);
int skx_adxl_get(void);
void skx_adxl_put(void);
void skx_set_decode(skx_decode_f decode, skx_show_retry_log_f show_retry_log);
void skx_set_decode(skx_decode_f decode);
void skx_set_show_rrl(skx_show_rrl_f rrl);
void skx_show_rrl(struct decoded_addr *res, char *msg, int len, bool scrub_err);
void skx_enable_rrl(bool enable);
void skx_set_mem_cfg(bool mem_cfg_2lm);
void skx_set_res_cfg(struct res_config *cfg);
void skx_init_mc_mapping(struct skx_dev *d);

View File

@ -446,11 +446,11 @@ static void x38_remove_one(struct pci_dev *pdev)
static const struct pci_device_id x38_pci_tbl[] = {
{
PCI_VEND_DEV(INTEL, X38_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
X38},
{
0,
} /* 0 terminated list. */
PCI_VEND_DEV(INTEL, X38_HB),
.driver_data = X38,
}, {
/* 0 terminated list. */
}
};
MODULE_DEVICE_TABLE(pci, x38_pci_tbl);

View File

@ -12,7 +12,6 @@ config AMD_ATL
depends on AMD_NB && X86_64 && RAS
depends on AMD_NODE
depends on MEMORY_FAILURE
default N
help
This library includes support for implementation-specific
address translation procedures needed for various error

View File

@ -184,6 +184,7 @@ static inline char *mc_event_error_type(const unsigned int err_type)
* @MEM_DDR5: Unbuffered DDR5 RAM
* @MEM_RDDR5: Registered DDR5 RAM
* @MEM_LRDDR5: Load-Reduced DDR5 memory.
* @MEM_LPDDR5: Low-Power DDR5 memory.
* @MEM_NVDIMM: Non-volatile RAM
* @MEM_WIO2: Wide I/O 2.
* @MEM_HBM2: High bandwidth Memory Gen 2.
@ -216,6 +217,7 @@ enum mem_type {
MEM_DDR5,
MEM_RDDR5,
MEM_LRDDR5,
MEM_LPDDR5,
MEM_NVDIMM,
MEM_WIO2,
MEM_HBM2,
@ -247,6 +249,7 @@ enum mem_type {
#define MEM_FLAG_DDR5 BIT(MEM_DDR5)
#define MEM_FLAG_RDDR5 BIT(MEM_RDDR5)
#define MEM_FLAG_LRDDR5 BIT(MEM_LRDDR5)
#define MEM_FLAG_LPDDR5 BIT(MEM_LPDDR5)
#define MEM_FLAG_NVDIMM BIT(MEM_NVDIMM)
#define MEM_FLAG_WIO2 BIT(MEM_WIO2)
#define MEM_FLAG_HBM2 BIT(MEM_HBM2)