mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 01:32:21 +02:00
- 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:
commit
4b5713ef2f
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user