summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-06-16 05:31:01 +0530
committerLinus Torvalds <torvalds@linux-foundation.org>2026-06-16 05:31:01 +0530
commit4b5713ef2f929dd8720fcdb66c063643ef9e3bcb (patch)
treee4760475adfa9bb2fc8b3e97c7b50e5a7d3bb80c /drivers
parent80476f22b8b7e193b26f285a7c9f9e4b63abca16 (diff)
parent2556746302b335b3a9b016e315c7a14f272eab12 (diff)
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 ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/edac/amd76x_edac.c16
-rw-r--r--drivers/edac/e752x_edac.c28
-rw-r--r--drivers/edac/e7xxx_edac.c28
-rw-r--r--drivers/edac/edac_mc.h4
-rw-r--r--drivers/edac/i10nm_base.c269
-rw-r--r--drivers/edac/i3000_edac.c10
-rw-r--r--drivers/edac/i3200_edac.c10
-rw-r--r--drivers/edac/i5000_edac.c33
-rw-r--r--drivers/edac/i5100_edac.c26
-rw-r--r--drivers/edac/i5400_edac.c33
-rw-r--r--drivers/edac/i7300_edac.c33
-rw-r--r--drivers/edac/i82860_edac.c10
-rw-r--r--drivers/edac/i82875p_edac.c12
-rw-r--r--drivers/edac/i82975x_edac.c11
-rw-r--r--drivers/edac/ie31200_edac.c86
-rw-r--r--drivers/edac/igen6_edac.c586
-rw-r--r--drivers/edac/imh_base.c81
-rw-r--r--drivers/edac/sb_edac.c2
-rw-r--r--drivers/edac/skx_base.c6
-rw-r--r--drivers/edac/skx_common.c297
-rw-r--r--drivers/edac/skx_common.h44
-rw-r--r--drivers/edac/x38_edac.c10
-rw-r--r--drivers/ras/amd/atl/Kconfig1
23 files changed, 1058 insertions, 578 deletions
diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c
index 2a49f68a7cf9..7bb11ffdb0c9 100644
--- a/drivers/edac/amd76x_edac.c
+++ b/drivers/edac/amd76x_edac.c
@@ -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);
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index 7221b4bb6df2..77c1fe75451e 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -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);
diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c
index 5852b95fa470..02071180b638 100644
--- a/drivers/edac/e7xxx_edac.c
+++ b/drivers/edac/e7xxx_edac.c
@@ -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);
diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h
index 881b00eadf7a..9505bbd41784 100644
--- a/drivers/edac/edac_mc.h
+++ b/drivers/edac/edac_mc.h
@@ -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
diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c
index 63df35444214..fa1853f252b0 100644
--- a/drivers/edac/i10nm_base.c
+++ b/drivers/edac/i10nm_base.c
@@ -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();
}
diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c
index 9065bc4386ff..04a231660b88 100644
--- a/drivers/edac/i3000_edac.c
+++ b/drivers/edac/i3000_edac.c
@@ -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);
diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c
index 6cade6d7ceff..d600b6c05217 100644
--- a/drivers/edac/i3200_edac.c
+++ b/drivers/edac/i3200_edac.c
@@ -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);
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c
index 471b8540d18b..c0faf55f7812 100644
--- a/drivers/edac/i5000_edac.c
+++ b/drivers/edac/i5000_edac.c
@@ -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);
diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c
index d470afe65001..d30919ceb22b 100644
--- a/drivers/edac/i5100_edac.c
+++ b/drivers/edac/i5100_edac.c
@@ -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;
diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c
index fb49a1d1df11..ae4f9298952d 100644
--- a/drivers/edac/i5400_edac.c
+++ b/drivers/edac/i5400_edac.c
@@ -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);
diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c
index 69068f8d0cad..64bc2d805a62 100644
--- a/drivers/edac/i7300_edac.c
+++ b/drivers/edac/i7300_edac.c
@@ -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 @@ fail0:
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);
diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c
index b8a497f0de28..e8c1ee80bba8 100644
--- a/drivers/edac/i82860_edac.c
+++ b/drivers/edac/i82860_edac.c
@@ -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);
diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c
index 553880b9fc12..869de8e372b3 100644
--- a/drivers/edac/i82875p_edac.c
+++ b/drivers/edac/i82875p_edac.c
@@ -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);
diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c
index d99f005832cf..09a79eaaa486 100644
--- a/drivers/edac/i82975x_edac.c
+++ b/drivers/edac/i82975x_edac.c
@@ -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);
diff --git a/drivers/edac/ie31200_edac.c b/drivers/edac/ie31200_edac.c
index a5dc4b88097f..e3bd6436669b 100644
--- a/drivers/edac/ie31200_edac.c
+++ b/drivers/edac/ie31200_edac.c
@@ -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);
diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c
index fcb8ab44cba5..f1fc20d4ebf6 100644
--- a/drivers/edac/igen6_edac.c
+++ b/drivers/edac/igen6_edac.c
@@ -122,6 +122,20 @@
#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)
+struct igen6_imc {
+ int mc;
+ struct mem_ctl_info *mci;
+ struct pci_dev *pdev;
+ struct device dev;
+ void __iomem *window;
+ u64 size;
+ u64 ch_s_size;
+ int ch_l_map;
+ u64 dimm_s_size[NUM_CHANNELS];
+ u64 dimm_l_size[NUM_CHANNELS];
+ int dimm_l_map[NUM_CHANNELS];
+};
+
static struct res_config {
bool machine_check;
/* The number of present memory controllers. */
@@ -134,12 +148,32 @@ static struct res_config {
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);
@@ -149,22 +183,9 @@ static struct res_config {
u64 (*err_addr_to_imc_addr)(u64 eaddr, int mc);
} *res_cfg;
-struct igen6_imc {
- int mc;
- struct mem_ctl_info *mci;
- struct pci_dev *pdev;
- struct device dev;
- void __iomem *window;
- u64 size;
- u64 ch_s_size;
- int ch_l_map;
- u64 dimm_s_size[NUM_CHANNELS];
- u64 dimm_l_size[NUM_CHANNELS];
- int dimm_l_map[NUM_CHANNELS];
-};
-
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 @@ fail3:
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 = {
diff --git a/drivers/edac/imh_base.c b/drivers/edac/imh_base.c
index 40082ba45e62..6ca0df031bf5 100644
--- a/drivers/edac/imh_base.c
+++ b/drivers/edac/imh_base.c
@@ -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");
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 7b282dfd093f..35eb7a2038ab 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -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;
}
diff --git a/drivers/edac/skx_base.c b/drivers/edac/skx_base.c
index aa6593ccda2d..de749413ff9a 100644
--- a/drivers/edac/skx_base.c
+++ b/drivers/edac/skx_base.c
@@ -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 */
diff --git a/drivers/edac/skx_common.c b/drivers/edac/skx_common.c
index a9557c8344bc..bfd0cd1689ed 100644
--- a/drivers/edac/skx_common.c
+++ b/drivers/edac/skx_common.c
@@ -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);
diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h
index f88038e5b18c..777252cca809 100644
--- a/drivers/edac/skx_common.h
+++ b/drivers/edac/skx_common.h
@@ -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);
diff --git a/drivers/edac/x38_edac.c b/drivers/edac/x38_edac.c
index 292dda754c23..2b55daca33b0 100644
--- a/drivers/edac/x38_edac.c
+++ b/drivers/edac/x38_edac.c
@@ -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);
diff --git a/drivers/ras/amd/atl/Kconfig b/drivers/ras/amd/atl/Kconfig
index 6e03942cd7da..44c2fd7febc5 100644
--- a/drivers/ras/amd/atl/Kconfig
+++ b/drivers/ras/amd/atl/Kconfig
@@ -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