Unverified Commit 727ed0bd authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!4230 [OLK-5.10] Intel: backport to support RAS EDAC feature on Granite...

!4230 [OLK-5.10] Intel: backport to support RAS EDAC feature on Granite Rapids(GNR) and Sierra Forest(SRF) server

Merge Pull Request from: @wjin123 
 
Title: [OLK-5.10] Intel: backport to support RAS EDAC feature on Granite Rapids(GNR) and Sierra Forest(SRF) server

Content:
Backport to kernel 5.10 to support RAS EDAC feature on Intel Granite Rapids(GNR) and Sierra Forest(SRF) server.
The backported upstream kernel commits lists as below:
0cfd8fba - x86/cpu: Fix Crestmont uarch
c545f5e4 - EDAC/i10nm: Skip the absent memory controllers
96ae3995 - EDAC/i10nm: Add Intel Sierra Forest server support
ba987eaa - EDAC/i10nm: Add Intel Granite Rapids server support
dd7814b7 - EDAC/i10nm: Make more configurations CPU model specific
The backported codes has been verified on Intel GNR/SRF server.

Intel-kernel issue:
https://gitee.com/openeuler/intel-kernel/issues/I8Y47N?from=project-issue

Test:
BIOS setting:
System Event Log -> WHEA Settings ->WHEA Support =Enable
System Event Log -> Error Injection Settings -> WHEA Error Injection Support = Enable
1.After GNR/SRF system power on, check if EDAC module installed with command "lsmod | grep -i edac", the EDAC module "i10nm_edac" should be found, i.e., "i10nm_edac 24576 0".
2. insert einj.ko kernel module with command "modprobe einj", then inject memory CE error with ras-tools command "./cmcistorm 1 1".
3. check EDAC message in dmesg, the EDAC message of detail CE memory error decoding info should be found in dmesg, similar as:"[  148.514145] EDAC MC3: 1 CE memory read error on CPU_SrcID#0_MC#3_Chan#0_DIMM#0 (channel:0 slot:0 page:0x11cc51 offset:0x480 grain:32 syndrome:0x0 -  err_code:0x0080:0x0090  SystemAddress:0x11cc51480 ProcessorSocketId:0x0 MemoryControllerId:0x3 ChannelAddress:0x1398a380 ChannelId:0x0 RankAddress:0x4e62880 PhysicalRankId:0x1 DimmSlotId:0x0 DimmRankId:0x1 Row:0x4e4 Column:0x100 Bank:0x3 BankGroup:0x7 ChipSelect:0x1)"

The ras-tools can be downloaded from below link:
https://git.kernel.org/pub/scm/linux/kernel/git/aegl/ras-tools.git

Known issue:
N/A

Default config change:
N/A
 
 
Link:https://gitee.com/openeuler/kernel/pulls/4230

 

Reviewed-by: default avatarJason Zeng <jason.zeng@intel.com>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parents f93722f7 1fe3c164
Loading
Loading
Loading
Loading
+348 −61
Original line number Diff line number Diff line
@@ -13,7 +13,7 @@
#include "edac_module.h"
#include "skx_common.h"

#define I10NM_REVISION	"v0.0.5"
#define I10NM_REVISION	"v0.0.6"
#define EDAC_MOD_STR	"i10nm_edac"

/* Debug macros */
@@ -23,24 +23,33 @@
#define I10NM_GET_SCK_BAR(d, reg)	\
	pci_read_config_dword((d)->uracu, 0xd0, &(reg))
#define I10NM_GET_IMC_BAR(d, i, reg)		\
	pci_read_config_dword((d)->uracu, 0xd8 + (i) * 4, &(reg))
	pci_read_config_dword((d)->uracu,	\
	(res_cfg->type == GNR ? 0xd4 : 0xd8) + (i) * 4, &(reg))
#define I10NM_GET_SAD(d, offset, i, reg)\
	pci_read_config_dword((d)->sad_all, (offset) + (i) * 8, &(reg))
	pci_read_config_dword((d)->sad_all, (offset) + (i) * \
	(res_cfg->type == GNR ? 12 : 8), &(reg))
#define I10NM_GET_HBM_IMC_BAR(d, reg)	\
	pci_read_config_dword((d)->uracu, 0xd4, &(reg))
#define I10NM_GET_CAPID3_CFG(d, reg)	\
	pci_read_config_dword((d)->pcu_cr3, 0x90, &(reg))
	pci_read_config_dword((d)->pcu_cr3,	\
	res_cfg->type == GNR ? 0x290 : 0x90, &(reg))
#define I10NM_GET_CAPID5_CFG(d, reg)	\
	pci_read_config_dword((d)->pcu_cr3,	\
	res_cfg->type == GNR ? 0x298 : 0x98, &(reg))
#define I10NM_GET_DIMMMTR(m, i, j)	\
	readl((m)->mbase + ((m)->hbm_mc ? 0x80c : 0x2080c) + \
	readl((m)->mbase + ((m)->hbm_mc ? 0x80c :	\
	(res_cfg->type == GNR ? 0xc0c : 0x2080c)) +	\
	(i) * (m)->chan_mmio_sz + (j) * 4)
#define I10NM_GET_MCDDRTCFG(m, i)	\
	readl((m)->mbase + ((m)->hbm_mc ? 0x970 : 0x20970) + \
	(i) * (m)->chan_mmio_sz)
#define I10NM_GET_MCMTR(m, i)		\
	readl((m)->mbase + ((m)->hbm_mc ? 0xef8 : 0x20ef8) + \
	readl((m)->mbase + ((m)->hbm_mc ? 0xef8 :	\
	(res_cfg->type == GNR ? 0xaf8 : 0x20ef8)) +	\
	(i) * (m)->chan_mmio_sz)
#define I10NM_GET_AMAP(m, i)		\
	readl((m)->mbase + ((m)->hbm_mc ? 0x814 : 0x20814) + \
	readl((m)->mbase + ((m)->hbm_mc ? 0x814 :	\
	(res_cfg->type == GNR ? 0xc14 : 0x20814)) +	\
	(i) * (m)->chan_mmio_sz)
#define I10NM_GET_REG32(m, i, offset)	\
	readl((m)->mbase + (i) * (m)->chan_mmio_sz + (offset))
@@ -56,7 +65,10 @@
#define I10NM_GET_HBM_IMC_MMIO_OFFSET(reg)	\
	((GET_BITFIELD(reg, 0, 10) << 12) + 0x140000)

#define I10NM_GNR_IMC_MMIO_OFFSET	0x24c000
#define I10NM_GNR_IMC_MMIO_SIZE		0x4000
#define I10NM_HBM_IMC_MMIO_SIZE		0x9000
#define I10NM_DDR_IMC_CH_CNT(reg)	GET_BITFIELD(reg, 21, 24)
#define I10NM_IS_HBM_PRESENT(reg)	GET_BITFIELD(reg, 27, 30)
#define I10NM_IS_HBM_IMC(reg)		GET_BITFIELD(reg, 29, 29)

@@ -148,20 +160,37 @@ static void __enable_retry_rd_err_log(struct skx_imc *imc, int chan, bool enable

static void enable_retry_rd_err_log(bool enable)
{
	int i, j, imc_num, chan_num;
	struct skx_imc *imc;
	struct skx_dev *d;
	int i, j;

	edac_dbg(2, "\n");

	list_for_each_entry(d, i10nm_edac_list, list)
		for (i = 0; i < I10NM_NUM_IMC; i++) {
	list_for_each_entry(d, i10nm_edac_list, list) {
		imc_num  = res_cfg->ddr_imc_num;
		chan_num = res_cfg->ddr_chan_num;

		for (i = 0; i < imc_num; i++) {
			imc = &d->imc[i];
			if (!imc->mbase)
				continue;

			for (j = 0; j < I10NM_NUM_CHANNELS; j++) {
				if (imc->hbm_mc) {
			for (j = 0; j < chan_num; j++)
				__enable_retry_rd_err_log(imc, j, enable,
							  res_cfg->offsets_scrub,
							  res_cfg->offsets_demand,
							  res_cfg->offsets_demand2);
		}

		imc_num += res_cfg->hbm_imc_num;
		chan_num = res_cfg->hbm_chan_num;

		for (; i < imc_num; i++) {
			imc = &d->imc[i];
			if (!imc->mbase || !imc->hbm_mc)
				continue;

			for (j = 0; j < chan_num; j++) {
				__enable_retry_rd_err_log(imc, j, enable,
							  res_cfg->offsets_scrub_hbm0,
							  res_cfg->offsets_demand_hbm0,
@@ -170,11 +199,6 @@ static void enable_retry_rd_err_log(bool enable)
							  res_cfg->offsets_scrub_hbm1,
							  res_cfg->offsets_demand_hbm1,
							  NULL);
				} else {
					__enable_retry_rd_err_log(imc, j, enable,
								  res_cfg->offsets_scrub,
								  res_cfg->offsets_demand,
								  res_cfg->offsets_demand2);
			}
		}
	}
@@ -311,6 +335,79 @@ static struct pci_dev *pci_get_dev_wrapper(int dom, unsigned int bus,
	return pdev;
}

/**
 * i10nm_get_imc_num() - Get the number of present DDR memory controllers.
 *
 * @cfg : The pointer to the structure of EDAC resource configurations.
 *
 * For Granite Rapids CPUs, the number of present DDR memory controllers read
 * at runtime overwrites the value statically configured in @cfg->ddr_imc_num.
 * For other CPUs, the number of present DDR memory controllers is statically
 * configured in @cfg->ddr_imc_num.
 *
 * RETURNS : 0 on success, < 0 on failure.
 */
static int i10nm_get_imc_num(struct res_config *cfg)
{
	int n, imc_num, chan_num = 0;
	struct skx_dev *d;
	u32 reg;

	list_for_each_entry(d, i10nm_edac_list, list) {
		d->pcu_cr3 = pci_get_dev_wrapper(d->seg, d->bus[res_cfg->pcu_cr3_bdf.bus],
						 res_cfg->pcu_cr3_bdf.dev,
						 res_cfg->pcu_cr3_bdf.fun);
		if (!d->pcu_cr3)
			continue;

		if (I10NM_GET_CAPID5_CFG(d, reg))
			continue;

		n = I10NM_DDR_IMC_CH_CNT(reg);

		if (!chan_num) {
			chan_num = n;
			edac_dbg(2, "Get DDR CH number: %d\n", chan_num);
		} else if (chan_num != n) {
			i10nm_printk(KERN_NOTICE, "Get DDR CH numbers: %d, %d\n", chan_num, n);
		}
	}

	switch (cfg->type) {
	case GNR:
		/*
		 * One channel per DDR memory controller for Granite Rapids CPUs.
		 */
		imc_num = chan_num;

		if (!imc_num) {
			i10nm_printk(KERN_ERR, "Invalid DDR MC number\n");
			return -ENODEV;
		}

		if (imc_num > I10NM_NUM_DDR_IMC) {
			i10nm_printk(KERN_ERR, "Need to make I10NM_NUM_DDR_IMC >= %d\n", imc_num);
			return -EINVAL;
		}

		if (cfg->ddr_imc_num != imc_num) {
			/*
			 * Store the number of present DDR memory controllers.
			 */
			cfg->ddr_imc_num = imc_num;
			edac_dbg(2, "Set DDR MC number: %d", imc_num);
		}

		return 0;
	default:
		/*
		 * For other CPUs, the number of present DDR memory controllers
		 * is statically pre-configured in cfg->ddr_imc_num.
		 */
		return 0;
	}
}

static bool i10nm_check_2lm(struct res_config *cfg)
{
	struct skx_dev *d;
@@ -318,9 +415,9 @@ static bool i10nm_check_2lm(struct res_config *cfg)
	int i;

	list_for_each_entry(d, i10nm_edac_list, list) {
		d->sad_all = pci_get_dev_wrapper(d->seg, d->bus[1],
						 PCI_SLOT(cfg->sad_all_devfn),
						 PCI_FUNC(cfg->sad_all_devfn));
		d->sad_all = pci_get_dev_wrapper(d->seg, d->bus[res_cfg->sad_all_bdf.bus],
						 res_cfg->sad_all_bdf.dev,
						 res_cfg->sad_all_bdf.fun);
		if (!d->sad_all)
			continue;

@@ -469,22 +566,154 @@ static bool i10nm_mc_decode(struct decoded_addr *res)
	return true;
}

/**
 * get_gnr_mdev() - Get the PCI device of the @logical_idx-th DDR memory controller.
 *
 * @d            : The pointer to the structure of CPU socket EDAC device.
 * @logical_idx  : The logical index of the present memory controller (0 ~ max present MC# - 1).
 * @physical_idx : To store the corresponding physical index of @logical_idx.
 *
 * RETURNS       : The PCI device of the @logical_idx-th DDR memory controller, NULL on failure.
 */
static struct pci_dev *get_gnr_mdev(struct skx_dev *d, int logical_idx, int *physical_idx)
{
#define GNR_MAX_IMC_PCI_CNT	28

	struct pci_dev *mdev;
	int i, logical = 0;

	/*
	 * Detect present memory controllers from { PCI device: 8-5, function 7-1 }
	 */
	for (i = 0; i < GNR_MAX_IMC_PCI_CNT; i++) {
		mdev = pci_get_dev_wrapper(d->seg,
					   d->bus[res_cfg->ddr_mdev_bdf.bus],
					   res_cfg->ddr_mdev_bdf.dev + i / 7,
					   res_cfg->ddr_mdev_bdf.fun + i % 7);

		if (mdev) {
			if (logical == logical_idx) {
				*physical_idx = i;
				return mdev;
			}

			pci_dev_put(mdev);
			logical++;
		}
	}

	return NULL;
}

/**
 * get_ddr_munit() - Get the resource of the i-th DDR memory controller.
 *
 * @d      : The pointer to the structure of CPU socket EDAC device.
 * @i      : The index of the CPU socket relative DDR memory controller.
 * @offset : To store the MMIO offset of the i-th DDR memory controller.
 * @size   : To store the MMIO size of the i-th DDR memory controller.
 *
 * RETURNS : The PCI device of the i-th DDR memory controller, NULL on failure.
 */
static struct pci_dev *get_ddr_munit(struct skx_dev *d, int i, u32 *offset, unsigned long *size)
{
	struct pci_dev *mdev;
	int physical_idx;
	u32 reg;

	switch (res_cfg->type) {
	case GNR:
		if (I10NM_GET_IMC_BAR(d, 0, reg)) {
			i10nm_printk(KERN_ERR, "Failed to get mc0 bar\n");
			return NULL;
		}

		mdev = get_gnr_mdev(d, i, &physical_idx);
		if (!mdev)
			return NULL;

		*offset = I10NM_GET_IMC_MMIO_OFFSET(reg) +
			  I10NM_GNR_IMC_MMIO_OFFSET +
			  physical_idx * I10NM_GNR_IMC_MMIO_SIZE;
		*size   = I10NM_GNR_IMC_MMIO_SIZE;

		break;
	default:
		if (I10NM_GET_IMC_BAR(d, i, reg)) {
			i10nm_printk(KERN_ERR, "Failed to get mc%d bar\n", i);
			return NULL;
		}

		mdev = pci_get_dev_wrapper(d->seg,
					   d->bus[res_cfg->ddr_mdev_bdf.bus],
					   res_cfg->ddr_mdev_bdf.dev + i,
					   res_cfg->ddr_mdev_bdf.fun);
		if (!mdev)
			return NULL;

		*offset  = I10NM_GET_IMC_MMIO_OFFSET(reg);
		*size    = I10NM_GET_IMC_MMIO_SIZE(reg);
	}

	return mdev;
}

/**
 * i10nm_imc_absent() - Check whether the memory controller @imc is absent
 *
 * @imc    : The pointer to the structure of memory controller EDAC device.
 *
 * RETURNS : true if the memory controller EDAC device is absent, false otherwise.
 */
static bool i10nm_imc_absent(struct skx_imc *imc)
{
	u32 mcmtr;
	int i;

	switch (res_cfg->type) {
	case SPR:
		for (i = 0; i < res_cfg->ddr_chan_num; i++) {
			mcmtr = I10NM_GET_MCMTR(imc, i);
			edac_dbg(1, "ch%d mcmtr reg %x\n", i, mcmtr);
			if (mcmtr != ~0)
				return false;
		}

		/*
		 * Some workstations' absent memory controllers still
		 * appear as PCIe devices, misleading the EDAC driver.
		 * By observing that the MMIO registers of these absent
		 * memory controllers consistently hold the value of ~0.
		 *
		 * We identify a memory controller as absent by checking
		 * if its MMIO register "mcmtr" == ~0 in all its channels.
		 */
		return true;
	default:
		return false;
	}
}

static int i10nm_get_ddr_munits(void)
{
	struct pci_dev *mdev;
	void __iomem *mbase;
	unsigned long size;
	struct skx_dev *d;
	int i, j = 0;
	int i, lmc, j = 0;
	u32 reg, off;
	u64 base;

	list_for_each_entry(d, i10nm_edac_list, list) {
		d->util_all = pci_get_dev_wrapper(d->seg, d->bus[1], 29, 1);
		d->util_all = pci_get_dev_wrapper(d->seg, d->bus[res_cfg->util_all_bdf.bus],
						  res_cfg->util_all_bdf.dev,
						  res_cfg->util_all_bdf.fun);
		if (!d->util_all)
			return -ENODEV;

		d->uracu = pci_get_dev_wrapper(d->seg, d->bus[0], 0, 1);
		d->uracu = pci_get_dev_wrapper(d->seg, d->bus[res_cfg->uracu_bdf.bus],
					       res_cfg->uracu_bdf.dev,
					       res_cfg->uracu_bdf.fun);
		if (!d->uracu)
			return -ENODEV;

@@ -497,9 +726,9 @@ static int i10nm_get_ddr_munits(void)
		edac_dbg(2, "socket%d mmio base 0x%llx (reg 0x%x)\n",
			 j++, base, reg);

		for (i = 0; i < I10NM_NUM_DDR_IMC; i++) {
			mdev = pci_get_dev_wrapper(d->seg, d->bus[0],
						   12 + i, 0);
		for (lmc = 0, i = 0; i < res_cfg->ddr_imc_num; i++) {
			mdev = get_ddr_munit(d, i, &off, &size);

			if (i == 0 && !mdev) {
				i10nm_printk(KERN_ERR, "No IMC found\n");
				return -ENODEV;
@@ -507,15 +736,6 @@ static int i10nm_get_ddr_munits(void)
			if (!mdev)
				continue;

			d->imc[i].mdev = mdev;

			if (I10NM_GET_IMC_BAR(d, i, reg)) {
				i10nm_printk(KERN_ERR, "Failed to get mc bar\n");
				return -ENODEV;
			}

			off  = I10NM_GET_IMC_MMIO_OFFSET(reg);
			size = I10NM_GET_IMC_MMIO_SIZE(reg);
			edac_dbg(2, "mc%d mmio base 0x%llx size 0x%lx (reg 0x%x)\n",
				 i, base + off, size, reg);

@@ -526,7 +746,17 @@ static int i10nm_get_ddr_munits(void)
				return -ENODEV;
			}

			d->imc[i].mbase = mbase;
			d->imc[lmc].mbase = mbase;
			if (i10nm_imc_absent(&d->imc[lmc])) {
				pci_dev_put(mdev);
				iounmap(mbase);
				d->imc[lmc].mbase = NULL;
				edac_dbg(2, "Skip absent mc%d\n", i);
				continue;
			} else {
				d->imc[lmc].mdev = mdev;
				lmc++;
			}
		}
	}

@@ -555,7 +785,6 @@ static int i10nm_get_hbm_munits(void)
	u64 base;

	list_for_each_entry(d, i10nm_edac_list, list) {
		d->pcu_cr3 = pci_get_dev_wrapper(d->seg, d->bus[1], 30, 3);
		if (!d->pcu_cr3)
			return -ENODEV;

@@ -576,11 +805,13 @@ static int i10nm_get_hbm_munits(void)
		}
		base += I10NM_GET_HBM_IMC_MMIO_OFFSET(reg);

		lmc = I10NM_NUM_DDR_IMC;
		lmc = res_cfg->ddr_imc_num;

		for (i = 0; i < res_cfg->hbm_imc_num; i++) {
			mdev = pci_get_dev_wrapper(d->seg, d->bus[res_cfg->hbm_mdev_bdf.bus],
						   res_cfg->hbm_mdev_bdf.dev + i / 4,
						   res_cfg->hbm_mdev_bdf.fun + i % 4);

		for (i = 0; i < I10NM_NUM_HBM_IMC; i++) {
			mdev = pci_get_dev_wrapper(d->seg, d->bus[0],
						   12 + i / 4, 1 + i % 4);
			if (i == 0 && !mdev) {
				i10nm_printk(KERN_ERR, "No hbm mc found\n");
				return -ENODEV;
@@ -630,8 +861,16 @@ static struct res_config i10nm_cfg0 = {
	.type			= I10NM,
	.decs_did		= 0x3452,
	.busno_cfg_offset	= 0xcc,
	.ddr_imc_num		= 4,
	.ddr_chan_num		= 2,
	.ddr_dimm_num		= 2,
	.ddr_chan_mmio_sz	= 0x4000,
	.sad_all_devfn		= PCI_DEVFN(29, 0),
	.sad_all_bdf		= {1, 29, 0},
	.pcu_cr3_bdf		= {1, 30, 3},
	.util_all_bdf		= {1, 29, 1},
	.uracu_bdf		= {0, 0, 1},
	.ddr_mdev_bdf		= {0, 12, 0},
	.hbm_mdev_bdf		= {0, 12, 1},
	.sad_all_offset		= 0x108,
	.offsets_scrub		= offsets_scrub_icx,
	.offsets_demand		= offsets_demand_icx,
@@ -641,8 +880,16 @@ static struct res_config i10nm_cfg1 = {
	.type			= I10NM,
	.decs_did		= 0x3452,
	.busno_cfg_offset	= 0xd0,
	.ddr_imc_num		= 4,
	.ddr_chan_num		= 2,
	.ddr_dimm_num		= 2,
	.ddr_chan_mmio_sz	= 0x4000,
	.sad_all_devfn		= PCI_DEVFN(29, 0),
	.sad_all_bdf		= {1, 29, 0},
	.pcu_cr3_bdf		= {1, 30, 3},
	.util_all_bdf		= {1, 29, 1},
	.uracu_bdf		= {0, 0, 1},
	.ddr_mdev_bdf		= {0, 12, 0},
	.hbm_mdev_bdf		= {0, 12, 1},
	.sad_all_offset		= 0x108,
	.offsets_scrub		= offsets_scrub_icx,
	.offsets_demand		= offsets_demand_icx,
@@ -652,10 +899,21 @@ static struct res_config spr_cfg = {
	.type			= SPR,
	.decs_did		= 0x3252,
	.busno_cfg_offset	= 0xd0,
	.ddr_imc_num		= 4,
	.ddr_chan_num		= 2,
	.ddr_dimm_num		= 2,
	.hbm_imc_num		= 16,
	.hbm_chan_num		= 2,
	.hbm_dimm_num		= 1,
	.ddr_chan_mmio_sz	= 0x8000,
	.hbm_chan_mmio_sz	= 0x4000,
	.support_ddr5		= true,
	.sad_all_devfn		= PCI_DEVFN(10, 0),
	.sad_all_bdf		= {1, 10, 0},
	.pcu_cr3_bdf		= {1, 30, 3},
	.util_all_bdf		= {1, 29, 1},
	.uracu_bdf		= {0, 0, 1},
	.ddr_mdev_bdf		= {0, 12, 0},
	.hbm_mdev_bdf		= {0, 12, 1},
	.sad_all_offset		= 0x300,
	.offsets_scrub		= offsets_scrub_spr,
	.offsets_scrub_hbm0	= offsets_scrub_spr_hbm0,
@@ -666,6 +924,23 @@ static struct res_config spr_cfg = {
	.offsets_demand_hbm1	= offsets_demand_spr_hbm1,
};

static struct res_config gnr_cfg = {
	.type			= GNR,
	.decs_did		= 0x3252,
	.busno_cfg_offset	= 0xd0,
	.ddr_imc_num		= 12,
	.ddr_chan_num		= 1,
	.ddr_dimm_num		= 2,
	.ddr_chan_mmio_sz	= 0x4000,
	.support_ddr5		= true,
	.sad_all_bdf		= {0, 13, 0},
	.pcu_cr3_bdf		= {0, 5, 0},
	.util_all_bdf		= {0, 13, 1},
	.uracu_bdf		= {0, 0, 1},
	.ddr_mdev_bdf		= {0, 5, 1},
	.sad_all_offset		= 0x300,
};

static const struct x86_cpu_id i10nm_cpuids[] = {
	X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(ATOM_TREMONT_D,	X86_STEPPINGS(0x0, 0x3), &i10nm_cfg0),
	X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(ATOM_TREMONT_D,	X86_STEPPINGS(0x4, 0xf), &i10nm_cfg1),
@@ -674,6 +949,8 @@ static const struct x86_cpu_id i10nm_cpuids[] = {
	X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(ICELAKE_D,		X86_STEPPINGS(0x0, 0xf), &i10nm_cfg1),
	X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(SAPPHIRERAPIDS_X,	X86_STEPPINGS(0x0, 0xf), &spr_cfg),
	X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(EMERALDRAPIDS_X,	X86_STEPPINGS(0x0, 0xf), &spr_cfg),
	X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(GRANITERAPIDS_X,	X86_STEPPINGS(0x0, 0xf), &gnr_cfg),
	X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(ATOM_CRESTMONT_X,	X86_STEPPINGS(0x0, 0xf), &gnr_cfg),
	{}
};
MODULE_DEVICE_TABLE(x86cpu, i10nm_cpuids);
@@ -693,7 +970,7 @@ static int i10nm_get_dimm_config(struct mem_ctl_info *mci,
{
	struct skx_pvt *pvt = mci->pvt_info;
	struct skx_imc *imc = pvt->imc;
	u32 mtr, amap, mcddrtcfg;
	u32 mtr, amap, mcddrtcfg = 0;
	struct dimm_info *dimm;
	int i, j, ndimms;

@@ -702,8 +979,11 @@ static int i10nm_get_dimm_config(struct mem_ctl_info *mci,
			continue;

		ndimms = 0;
		mcddrtcfg = I10NM_GET_MCDDRTCFG(imc, i);
		amap = I10NM_GET_AMAP(imc, i);

		if (res_cfg->type != GNR)
			mcddrtcfg = I10NM_GET_MCDDRTCFG(imc, i);

		for (j = 0; j < imc->num_dimms; j++) {
			dimm = edac_get_dimm(mci, i, j, 0);
			mtr = I10NM_GET_DIMMMTR(imc, i, j);
@@ -789,6 +1069,7 @@ static int __init i10nm_init(void)
	struct skx_dev *d;
	int rc, i, off[3] = {0xd0, 0xc8, 0xcc};
	u64 tolm, tohm;
	int imc_num;

	edac_dbg(2, "\n");

@@ -818,6 +1099,10 @@ static int __init i10nm_init(void)
		return -ENODEV;
	}

	rc = i10nm_get_imc_num(cfg);
	if (rc < 0)
		goto fail;

	mem_cfg_2lm = i10nm_check_2lm(cfg);
	skx_set_mem_cfg(mem_cfg_2lm);

@@ -826,6 +1111,8 @@ static int __init i10nm_init(void)
	if (i10nm_get_hbm_munits() && rc)
		goto fail;

	imc_num = res_cfg->ddr_imc_num + res_cfg->hbm_imc_num;

	list_for_each_entry(d, i10nm_edac_list, list) {
		rc = skx_get_src_id(d, 0xf8, &src_id);
		if (rc < 0)
@@ -836,7 +1123,7 @@ static int __init i10nm_init(void)
			goto fail;

		edac_dbg(2, "src_id = %d node_id = %d\n", src_id, node_id);
		for (i = 0; i < I10NM_NUM_IMC; i++) {
		for (i = 0; i < imc_num; i++) {
			if (!d->imc[i].mdev)
				continue;

@@ -846,12 +1133,12 @@ static int __init i10nm_init(void)
			d->imc[i].node_id = node_id;
			if (d->imc[i].hbm_mc) {
				d->imc[i].chan_mmio_sz = cfg->hbm_chan_mmio_sz;
				d->imc[i].num_channels = I10NM_NUM_HBM_CHANNELS;
				d->imc[i].num_dimms    = I10NM_NUM_HBM_DIMMS;
				d->imc[i].num_channels = cfg->hbm_chan_num;
				d->imc[i].num_dimms    = cfg->hbm_dimm_num;
			} else {
				d->imc[i].chan_mmio_sz = cfg->ddr_chan_mmio_sz;
				d->imc[i].num_channels = I10NM_NUM_DDR_CHANNELS;
				d->imc[i].num_dimms    = I10NM_NUM_DDR_DIMMS;
				d->imc[i].num_channels = cfg->ddr_chan_num;
				d->imc[i].num_dimms    = cfg->ddr_dimm_num;
			}

			rc = skx_register_mci(&d->imc[i], d->imc[i].mdev,
+33 −4
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@
#define SKX_NUM_CHANNELS	3	/* Channels per memory controller */
#define SKX_NUM_DIMMS		2	/* Max DIMMS per channel */

#define I10NM_NUM_DDR_IMC	4
#define I10NM_NUM_DDR_IMC	12
#define I10NM_NUM_DDR_CHANNELS	2
#define I10NM_NUM_DDR_DIMMS	2

@@ -129,7 +129,8 @@ struct skx_pvt {
enum type {
	SKX,
	I10NM,
	SPR
	SPR,
	GNR
};

enum {
@@ -173,19 +174,47 @@ struct decoded_addr {
	bool	decoded_by_adxl;
};

struct pci_bdf {
	u32 bus : 8;
	u32 dev : 5;
	u32 fun : 3;
};

struct res_config {
	enum type type;
	/* Configuration agent device ID */
	unsigned int decs_did;
	/* Default bus number configuration register offset */
	int busno_cfg_offset;
	/* DDR memory controllers per socket */
	int ddr_imc_num;
	/* DDR channels per DDR memory controller */
	int ddr_chan_num;
	/* DDR DIMMs per DDR memory channel */
	int ddr_dimm_num;
	/* Per DDR channel memory-mapped I/O size */
	int ddr_chan_mmio_sz;
	/* HBM memory controllers per socket */
	int hbm_imc_num;
	/* HBM channels per HBM memory controller */
	int hbm_chan_num;
	/* HBM DIMMs per HBM memory channel */
	int hbm_dimm_num;
	/* Per HBM channel memory-mapped I/O size */
	int hbm_chan_mmio_sz;
	bool support_ddr5;
	/* SAD device number and function number */
	unsigned int sad_all_devfn;
	/* SAD device BDF */
	struct pci_bdf sad_all_bdf;
	/* PCU device BDF */
	struct pci_bdf pcu_cr3_bdf;
	/* UTIL device BDF */
	struct pci_bdf util_all_bdf;
	/* URACU device BDF */
	struct pci_bdf uracu_bdf;
	/* DDR mdev device BDF */
	struct pci_bdf ddr_mdev_bdf;
	/* HBM mdev device BDF */
	struct pci_bdf hbm_mdev_bdf;
	int sad_all_offset;
	/* Offsets of retry_rd_err_log registers */
	u32 *offsets_scrub;