18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/* Intel Sandy Bridge -EN/-EP/-EX Memory Controller kernel module
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This driver supports the memory controllers found on the Intel
58c2ecf20Sopenharmony_ci * processor family Sandy Bridge.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (c) 2011 by:
88c2ecf20Sopenharmony_ci *	 Mauro Carvalho Chehab
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/init.h>
138c2ecf20Sopenharmony_ci#include <linux/pci.h>
148c2ecf20Sopenharmony_ci#include <linux/pci_ids.h>
158c2ecf20Sopenharmony_ci#include <linux/slab.h>
168c2ecf20Sopenharmony_ci#include <linux/delay.h>
178c2ecf20Sopenharmony_ci#include <linux/edac.h>
188c2ecf20Sopenharmony_ci#include <linux/mmzone.h>
198c2ecf20Sopenharmony_ci#include <linux/smp.h>
208c2ecf20Sopenharmony_ci#include <linux/bitmap.h>
218c2ecf20Sopenharmony_ci#include <linux/math64.h>
228c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h>
238c2ecf20Sopenharmony_ci#include <asm/cpu_device_id.h>
248c2ecf20Sopenharmony_ci#include <asm/intel-family.h>
258c2ecf20Sopenharmony_ci#include <asm/processor.h>
268c2ecf20Sopenharmony_ci#include <asm/mce.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include "edac_module.h"
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/* Static vars */
318c2ecf20Sopenharmony_cistatic LIST_HEAD(sbridge_edac_list);
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/*
348c2ecf20Sopenharmony_ci * Alter this version for the module when modifications are made
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_ci#define SBRIDGE_REVISION    " Ver: 1.1.2 "
378c2ecf20Sopenharmony_ci#define EDAC_MOD_STR	    "sb_edac"
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/*
408c2ecf20Sopenharmony_ci * Debug macros
418c2ecf20Sopenharmony_ci */
428c2ecf20Sopenharmony_ci#define sbridge_printk(level, fmt, arg...)			\
438c2ecf20Sopenharmony_ci	edac_printk(level, "sbridge", fmt, ##arg)
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#define sbridge_mc_printk(mci, level, fmt, arg...)		\
468c2ecf20Sopenharmony_ci	edac_mc_chipset_printk(mci, level, "sbridge", fmt, ##arg)
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/*
498c2ecf20Sopenharmony_ci * Get a bit field at register value <v>, from bit <lo> to bit <hi>
508c2ecf20Sopenharmony_ci */
518c2ecf20Sopenharmony_ci#define GET_BITFIELD(v, lo, hi)	\
528c2ecf20Sopenharmony_ci	(((v) & GENMASK_ULL(hi, lo)) >> (lo))
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci/* Devices 12 Function 6, Offsets 0x80 to 0xcc */
558c2ecf20Sopenharmony_cistatic const u32 sbridge_dram_rule[] = {
568c2ecf20Sopenharmony_ci	0x80, 0x88, 0x90, 0x98, 0xa0,
578c2ecf20Sopenharmony_ci	0xa8, 0xb0, 0xb8, 0xc0, 0xc8,
588c2ecf20Sopenharmony_ci};
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic const u32 ibridge_dram_rule[] = {
618c2ecf20Sopenharmony_ci	0x60, 0x68, 0x70, 0x78, 0x80,
628c2ecf20Sopenharmony_ci	0x88, 0x90, 0x98, 0xa0,	0xa8,
638c2ecf20Sopenharmony_ci	0xb0, 0xb8, 0xc0, 0xc8, 0xd0,
648c2ecf20Sopenharmony_ci	0xd8, 0xe0, 0xe8, 0xf0, 0xf8,
658c2ecf20Sopenharmony_ci};
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic const u32 knl_dram_rule[] = {
688c2ecf20Sopenharmony_ci	0x60, 0x68, 0x70, 0x78, 0x80, /* 0-4 */
698c2ecf20Sopenharmony_ci	0x88, 0x90, 0x98, 0xa0, 0xa8, /* 5-9 */
708c2ecf20Sopenharmony_ci	0xb0, 0xb8, 0xc0, 0xc8, 0xd0, /* 10-14 */
718c2ecf20Sopenharmony_ci	0xd8, 0xe0, 0xe8, 0xf0, 0xf8, /* 15-19 */
728c2ecf20Sopenharmony_ci	0x100, 0x108, 0x110, 0x118,   /* 20-23 */
738c2ecf20Sopenharmony_ci};
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci#define DRAM_RULE_ENABLE(reg)	GET_BITFIELD(reg, 0,  0)
768c2ecf20Sopenharmony_ci#define A7MODE(reg)		GET_BITFIELD(reg, 26, 26)
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic char *show_dram_attr(u32 attr)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	switch (attr) {
818c2ecf20Sopenharmony_ci		case 0:
828c2ecf20Sopenharmony_ci			return "DRAM";
838c2ecf20Sopenharmony_ci		case 1:
848c2ecf20Sopenharmony_ci			return "MMCFG";
858c2ecf20Sopenharmony_ci		case 2:
868c2ecf20Sopenharmony_ci			return "NXM";
878c2ecf20Sopenharmony_ci		default:
888c2ecf20Sopenharmony_ci			return "unknown";
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic const u32 sbridge_interleave_list[] = {
938c2ecf20Sopenharmony_ci	0x84, 0x8c, 0x94, 0x9c, 0xa4,
948c2ecf20Sopenharmony_ci	0xac, 0xb4, 0xbc, 0xc4, 0xcc,
958c2ecf20Sopenharmony_ci};
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cistatic const u32 ibridge_interleave_list[] = {
988c2ecf20Sopenharmony_ci	0x64, 0x6c, 0x74, 0x7c, 0x84,
998c2ecf20Sopenharmony_ci	0x8c, 0x94, 0x9c, 0xa4, 0xac,
1008c2ecf20Sopenharmony_ci	0xb4, 0xbc, 0xc4, 0xcc, 0xd4,
1018c2ecf20Sopenharmony_ci	0xdc, 0xe4, 0xec, 0xf4, 0xfc,
1028c2ecf20Sopenharmony_ci};
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic const u32 knl_interleave_list[] = {
1058c2ecf20Sopenharmony_ci	0x64, 0x6c, 0x74, 0x7c, 0x84, /* 0-4 */
1068c2ecf20Sopenharmony_ci	0x8c, 0x94, 0x9c, 0xa4, 0xac, /* 5-9 */
1078c2ecf20Sopenharmony_ci	0xb4, 0xbc, 0xc4, 0xcc, 0xd4, /* 10-14 */
1088c2ecf20Sopenharmony_ci	0xdc, 0xe4, 0xec, 0xf4, 0xfc, /* 15-19 */
1098c2ecf20Sopenharmony_ci	0x104, 0x10c, 0x114, 0x11c,   /* 20-23 */
1108c2ecf20Sopenharmony_ci};
1118c2ecf20Sopenharmony_ci#define MAX_INTERLEAVE							\
1128c2ecf20Sopenharmony_ci	(max_t(unsigned int, ARRAY_SIZE(sbridge_interleave_list),	\
1138c2ecf20Sopenharmony_ci	       max_t(unsigned int, ARRAY_SIZE(ibridge_interleave_list),	\
1148c2ecf20Sopenharmony_ci		     ARRAY_SIZE(knl_interleave_list))))
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistruct interleave_pkg {
1178c2ecf20Sopenharmony_ci	unsigned char start;
1188c2ecf20Sopenharmony_ci	unsigned char end;
1198c2ecf20Sopenharmony_ci};
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic const struct interleave_pkg sbridge_interleave_pkg[] = {
1228c2ecf20Sopenharmony_ci	{ 0, 2 },
1238c2ecf20Sopenharmony_ci	{ 3, 5 },
1248c2ecf20Sopenharmony_ci	{ 8, 10 },
1258c2ecf20Sopenharmony_ci	{ 11, 13 },
1268c2ecf20Sopenharmony_ci	{ 16, 18 },
1278c2ecf20Sopenharmony_ci	{ 19, 21 },
1288c2ecf20Sopenharmony_ci	{ 24, 26 },
1298c2ecf20Sopenharmony_ci	{ 27, 29 },
1308c2ecf20Sopenharmony_ci};
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic const struct interleave_pkg ibridge_interleave_pkg[] = {
1338c2ecf20Sopenharmony_ci	{ 0, 3 },
1348c2ecf20Sopenharmony_ci	{ 4, 7 },
1358c2ecf20Sopenharmony_ci	{ 8, 11 },
1368c2ecf20Sopenharmony_ci	{ 12, 15 },
1378c2ecf20Sopenharmony_ci	{ 16, 19 },
1388c2ecf20Sopenharmony_ci	{ 20, 23 },
1398c2ecf20Sopenharmony_ci	{ 24, 27 },
1408c2ecf20Sopenharmony_ci	{ 28, 31 },
1418c2ecf20Sopenharmony_ci};
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic inline int sad_pkg(const struct interleave_pkg *table, u32 reg,
1448c2ecf20Sopenharmony_ci			  int interleave)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	return GET_BITFIELD(reg, table[interleave].start,
1478c2ecf20Sopenharmony_ci			    table[interleave].end);
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci/* Devices 12 Function 7 */
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci#define TOLM		0x80
1538c2ecf20Sopenharmony_ci#define TOHM		0x84
1548c2ecf20Sopenharmony_ci#define HASWELL_TOLM	0xd0
1558c2ecf20Sopenharmony_ci#define HASWELL_TOHM_0	0xd4
1568c2ecf20Sopenharmony_ci#define HASWELL_TOHM_1	0xd8
1578c2ecf20Sopenharmony_ci#define KNL_TOLM	0xd0
1588c2ecf20Sopenharmony_ci#define KNL_TOHM_0	0xd4
1598c2ecf20Sopenharmony_ci#define KNL_TOHM_1	0xd8
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci#define GET_TOLM(reg)		((GET_BITFIELD(reg, 0,  3) << 28) | 0x3ffffff)
1628c2ecf20Sopenharmony_ci#define GET_TOHM(reg)		((GET_BITFIELD(reg, 0, 20) << 25) | 0x3ffffff)
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci/* Device 13 Function 6 */
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci#define SAD_TARGET	0xf0
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci#define SOURCE_ID(reg)		GET_BITFIELD(reg, 9, 11)
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci#define SOURCE_ID_KNL(reg)	GET_BITFIELD(reg, 12, 14)
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci#define SAD_CONTROL	0xf4
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci/* Device 14 function 0 */
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic const u32 tad_dram_rule[] = {
1778c2ecf20Sopenharmony_ci	0x40, 0x44, 0x48, 0x4c,
1788c2ecf20Sopenharmony_ci	0x50, 0x54, 0x58, 0x5c,
1798c2ecf20Sopenharmony_ci	0x60, 0x64, 0x68, 0x6c,
1808c2ecf20Sopenharmony_ci};
1818c2ecf20Sopenharmony_ci#define MAX_TAD	ARRAY_SIZE(tad_dram_rule)
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci#define TAD_LIMIT(reg)		((GET_BITFIELD(reg, 12, 31) << 26) | 0x3ffffff)
1848c2ecf20Sopenharmony_ci#define TAD_SOCK(reg)		GET_BITFIELD(reg, 10, 11)
1858c2ecf20Sopenharmony_ci#define TAD_CH(reg)		GET_BITFIELD(reg,  8,  9)
1868c2ecf20Sopenharmony_ci#define TAD_TGT3(reg)		GET_BITFIELD(reg,  6,  7)
1878c2ecf20Sopenharmony_ci#define TAD_TGT2(reg)		GET_BITFIELD(reg,  4,  5)
1888c2ecf20Sopenharmony_ci#define TAD_TGT1(reg)		GET_BITFIELD(reg,  2,  3)
1898c2ecf20Sopenharmony_ci#define TAD_TGT0(reg)		GET_BITFIELD(reg,  0,  1)
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci/* Device 15, function 0 */
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci#define MCMTR			0x7c
1948c2ecf20Sopenharmony_ci#define KNL_MCMTR		0x624
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci#define IS_ECC_ENABLED(mcmtr)		GET_BITFIELD(mcmtr, 2, 2)
1978c2ecf20Sopenharmony_ci#define IS_LOCKSTEP_ENABLED(mcmtr)	GET_BITFIELD(mcmtr, 1, 1)
1988c2ecf20Sopenharmony_ci#define IS_CLOSE_PG(mcmtr)		GET_BITFIELD(mcmtr, 0, 0)
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci/* Device 15, function 1 */
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci#define RASENABLES		0xac
2038c2ecf20Sopenharmony_ci#define IS_MIRROR_ENABLED(reg)		GET_BITFIELD(reg, 0, 0)
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci/* Device 15, functions 2-5 */
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cistatic const int mtr_regs[] = {
2088c2ecf20Sopenharmony_ci	0x80, 0x84, 0x88,
2098c2ecf20Sopenharmony_ci};
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic const int knl_mtr_reg = 0xb60;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci#define RANK_DISABLE(mtr)		GET_BITFIELD(mtr, 16, 19)
2148c2ecf20Sopenharmony_ci#define IS_DIMM_PRESENT(mtr)		GET_BITFIELD(mtr, 14, 14)
2158c2ecf20Sopenharmony_ci#define RANK_CNT_BITS(mtr)		GET_BITFIELD(mtr, 12, 13)
2168c2ecf20Sopenharmony_ci#define RANK_WIDTH_BITS(mtr)		GET_BITFIELD(mtr, 2, 4)
2178c2ecf20Sopenharmony_ci#define COL_WIDTH_BITS(mtr)		GET_BITFIELD(mtr, 0, 1)
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic const u32 tad_ch_nilv_offset[] = {
2208c2ecf20Sopenharmony_ci	0x90, 0x94, 0x98, 0x9c,
2218c2ecf20Sopenharmony_ci	0xa0, 0xa4, 0xa8, 0xac,
2228c2ecf20Sopenharmony_ci	0xb0, 0xb4, 0xb8, 0xbc,
2238c2ecf20Sopenharmony_ci};
2248c2ecf20Sopenharmony_ci#define CHN_IDX_OFFSET(reg)		GET_BITFIELD(reg, 28, 29)
2258c2ecf20Sopenharmony_ci#define TAD_OFFSET(reg)			(GET_BITFIELD(reg,  6, 25) << 26)
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic const u32 rir_way_limit[] = {
2288c2ecf20Sopenharmony_ci	0x108, 0x10c, 0x110, 0x114, 0x118,
2298c2ecf20Sopenharmony_ci};
2308c2ecf20Sopenharmony_ci#define MAX_RIR_RANGES ARRAY_SIZE(rir_way_limit)
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci#define IS_RIR_VALID(reg)	GET_BITFIELD(reg, 31, 31)
2338c2ecf20Sopenharmony_ci#define RIR_WAY(reg)		GET_BITFIELD(reg, 28, 29)
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci#define MAX_RIR_WAY	8
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic const u32 rir_offset[MAX_RIR_RANGES][MAX_RIR_WAY] = {
2388c2ecf20Sopenharmony_ci	{ 0x120, 0x124, 0x128, 0x12c, 0x130, 0x134, 0x138, 0x13c },
2398c2ecf20Sopenharmony_ci	{ 0x140, 0x144, 0x148, 0x14c, 0x150, 0x154, 0x158, 0x15c },
2408c2ecf20Sopenharmony_ci	{ 0x160, 0x164, 0x168, 0x16c, 0x170, 0x174, 0x178, 0x17c },
2418c2ecf20Sopenharmony_ci	{ 0x180, 0x184, 0x188, 0x18c, 0x190, 0x194, 0x198, 0x19c },
2428c2ecf20Sopenharmony_ci	{ 0x1a0, 0x1a4, 0x1a8, 0x1ac, 0x1b0, 0x1b4, 0x1b8, 0x1bc },
2438c2ecf20Sopenharmony_ci};
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci#define RIR_RNK_TGT(type, reg) (((type) == BROADWELL) ? \
2468c2ecf20Sopenharmony_ci	GET_BITFIELD(reg, 20, 23) : GET_BITFIELD(reg, 16, 19))
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci#define RIR_OFFSET(type, reg) (((type) == HASWELL || (type) == BROADWELL) ? \
2498c2ecf20Sopenharmony_ci	GET_BITFIELD(reg,  2, 15) : GET_BITFIELD(reg,  2, 14))
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci/* Device 16, functions 2-7 */
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci/*
2548c2ecf20Sopenharmony_ci * FIXME: Implement the error count reads directly
2558c2ecf20Sopenharmony_ci */
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci#define RANK_ODD_OV(reg)		GET_BITFIELD(reg, 31, 31)
2588c2ecf20Sopenharmony_ci#define RANK_ODD_ERR_CNT(reg)		GET_BITFIELD(reg, 16, 30)
2598c2ecf20Sopenharmony_ci#define RANK_EVEN_OV(reg)		GET_BITFIELD(reg, 15, 15)
2608c2ecf20Sopenharmony_ci#define RANK_EVEN_ERR_CNT(reg)		GET_BITFIELD(reg,  0, 14)
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci#if 0 /* Currently unused*/
2638c2ecf20Sopenharmony_cistatic const u32 correrrcnt[] = {
2648c2ecf20Sopenharmony_ci	0x104, 0x108, 0x10c, 0x110,
2658c2ecf20Sopenharmony_ci};
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_cistatic const u32 correrrthrsld[] = {
2688c2ecf20Sopenharmony_ci	0x11c, 0x120, 0x124, 0x128,
2698c2ecf20Sopenharmony_ci};
2708c2ecf20Sopenharmony_ci#endif
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci#define RANK_ODD_ERR_THRSLD(reg)	GET_BITFIELD(reg, 16, 30)
2738c2ecf20Sopenharmony_ci#define RANK_EVEN_ERR_THRSLD(reg)	GET_BITFIELD(reg,  0, 14)
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci/* Device 17, function 0 */
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci#define SB_RANK_CFG_A		0x0328
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci#define IB_RANK_CFG_A		0x0320
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci/*
2838c2ecf20Sopenharmony_ci * sbridge structs
2848c2ecf20Sopenharmony_ci */
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci#define NUM_CHANNELS		6	/* Max channels per MC */
2878c2ecf20Sopenharmony_ci#define MAX_DIMMS		3	/* Max DIMMS per channel */
2888c2ecf20Sopenharmony_ci#define KNL_MAX_CHAS		38	/* KNL max num. of Cache Home Agents */
2898c2ecf20Sopenharmony_ci#define KNL_MAX_CHANNELS	6	/* KNL max num. of PCI channels */
2908c2ecf20Sopenharmony_ci#define KNL_MAX_EDCS		8	/* Embedded DRAM controllers */
2918c2ecf20Sopenharmony_ci#define CHANNEL_UNSPECIFIED	0xf	/* Intel IA32 SDM 15-14 */
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_cienum type {
2948c2ecf20Sopenharmony_ci	SANDY_BRIDGE,
2958c2ecf20Sopenharmony_ci	IVY_BRIDGE,
2968c2ecf20Sopenharmony_ci	HASWELL,
2978c2ecf20Sopenharmony_ci	BROADWELL,
2988c2ecf20Sopenharmony_ci	KNIGHTS_LANDING,
2998c2ecf20Sopenharmony_ci};
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_cienum domain {
3028c2ecf20Sopenharmony_ci	IMC0 = 0,
3038c2ecf20Sopenharmony_ci	IMC1,
3048c2ecf20Sopenharmony_ci	SOCK,
3058c2ecf20Sopenharmony_ci};
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_cienum mirroring_mode {
3088c2ecf20Sopenharmony_ci	NON_MIRRORING,
3098c2ecf20Sopenharmony_ci	ADDR_RANGE_MIRRORING,
3108c2ecf20Sopenharmony_ci	FULL_MIRRORING,
3118c2ecf20Sopenharmony_ci};
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistruct sbridge_pvt;
3148c2ecf20Sopenharmony_cistruct sbridge_info {
3158c2ecf20Sopenharmony_ci	enum type	type;
3168c2ecf20Sopenharmony_ci	u32		mcmtr;
3178c2ecf20Sopenharmony_ci	u32		rankcfgr;
3188c2ecf20Sopenharmony_ci	u64		(*get_tolm)(struct sbridge_pvt *pvt);
3198c2ecf20Sopenharmony_ci	u64		(*get_tohm)(struct sbridge_pvt *pvt);
3208c2ecf20Sopenharmony_ci	u64		(*rir_limit)(u32 reg);
3218c2ecf20Sopenharmony_ci	u64		(*sad_limit)(u32 reg);
3228c2ecf20Sopenharmony_ci	u32		(*interleave_mode)(u32 reg);
3238c2ecf20Sopenharmony_ci	u32		(*dram_attr)(u32 reg);
3248c2ecf20Sopenharmony_ci	const u32	*dram_rule;
3258c2ecf20Sopenharmony_ci	const u32	*interleave_list;
3268c2ecf20Sopenharmony_ci	const struct interleave_pkg *interleave_pkg;
3278c2ecf20Sopenharmony_ci	u8		max_sad;
3288c2ecf20Sopenharmony_ci	u8		(*get_node_id)(struct sbridge_pvt *pvt);
3298c2ecf20Sopenharmony_ci	u8		(*get_ha)(u8 bank);
3308c2ecf20Sopenharmony_ci	enum mem_type	(*get_memory_type)(struct sbridge_pvt *pvt);
3318c2ecf20Sopenharmony_ci	enum dev_type	(*get_width)(struct sbridge_pvt *pvt, u32 mtr);
3328c2ecf20Sopenharmony_ci	struct pci_dev	*pci_vtd;
3338c2ecf20Sopenharmony_ci};
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistruct sbridge_channel {
3368c2ecf20Sopenharmony_ci	u32		ranks;
3378c2ecf20Sopenharmony_ci	u32		dimms;
3388c2ecf20Sopenharmony_ci};
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_cistruct pci_id_descr {
3418c2ecf20Sopenharmony_ci	int			dev_id;
3428c2ecf20Sopenharmony_ci	int			optional;
3438c2ecf20Sopenharmony_ci	enum domain		dom;
3448c2ecf20Sopenharmony_ci};
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistruct pci_id_table {
3478c2ecf20Sopenharmony_ci	const struct pci_id_descr	*descr;
3488c2ecf20Sopenharmony_ci	int				n_devs_per_imc;
3498c2ecf20Sopenharmony_ci	int				n_devs_per_sock;
3508c2ecf20Sopenharmony_ci	int				n_imcs_per_sock;
3518c2ecf20Sopenharmony_ci	enum type			type;
3528c2ecf20Sopenharmony_ci};
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_cistruct sbridge_dev {
3558c2ecf20Sopenharmony_ci	struct list_head	list;
3568c2ecf20Sopenharmony_ci	int			seg;
3578c2ecf20Sopenharmony_ci	u8			bus, mc;
3588c2ecf20Sopenharmony_ci	u8			node_id, source_id;
3598c2ecf20Sopenharmony_ci	struct pci_dev		**pdev;
3608c2ecf20Sopenharmony_ci	enum domain		dom;
3618c2ecf20Sopenharmony_ci	int			n_devs;
3628c2ecf20Sopenharmony_ci	int			i_devs;
3638c2ecf20Sopenharmony_ci	struct mem_ctl_info	*mci;
3648c2ecf20Sopenharmony_ci};
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_cistruct knl_pvt {
3678c2ecf20Sopenharmony_ci	struct pci_dev          *pci_cha[KNL_MAX_CHAS];
3688c2ecf20Sopenharmony_ci	struct pci_dev          *pci_channel[KNL_MAX_CHANNELS];
3698c2ecf20Sopenharmony_ci	struct pci_dev          *pci_mc0;
3708c2ecf20Sopenharmony_ci	struct pci_dev          *pci_mc1;
3718c2ecf20Sopenharmony_ci	struct pci_dev          *pci_mc0_misc;
3728c2ecf20Sopenharmony_ci	struct pci_dev          *pci_mc1_misc;
3738c2ecf20Sopenharmony_ci	struct pci_dev          *pci_mc_info; /* tolm, tohm */
3748c2ecf20Sopenharmony_ci};
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_cistruct sbridge_pvt {
3778c2ecf20Sopenharmony_ci	/* Devices per socket */
3788c2ecf20Sopenharmony_ci	struct pci_dev		*pci_ddrio;
3798c2ecf20Sopenharmony_ci	struct pci_dev		*pci_sad0, *pci_sad1;
3808c2ecf20Sopenharmony_ci	struct pci_dev		*pci_br0, *pci_br1;
3818c2ecf20Sopenharmony_ci	/* Devices per memory controller */
3828c2ecf20Sopenharmony_ci	struct pci_dev		*pci_ha, *pci_ta, *pci_ras;
3838c2ecf20Sopenharmony_ci	struct pci_dev		*pci_tad[NUM_CHANNELS];
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	struct sbridge_dev	*sbridge_dev;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	struct sbridge_info	info;
3888c2ecf20Sopenharmony_ci	struct sbridge_channel	channel[NUM_CHANNELS];
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	/* Memory type detection */
3918c2ecf20Sopenharmony_ci	bool			is_cur_addr_mirrored, is_lockstep, is_close_pg;
3928c2ecf20Sopenharmony_ci	bool			is_chan_hash;
3938c2ecf20Sopenharmony_ci	enum mirroring_mode	mirror_mode;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	/* Memory description */
3968c2ecf20Sopenharmony_ci	u64			tolm, tohm;
3978c2ecf20Sopenharmony_ci	struct knl_pvt knl;
3988c2ecf20Sopenharmony_ci};
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci#define PCI_DESCR(device_id, opt, domain)	\
4018c2ecf20Sopenharmony_ci	.dev_id = (device_id),		\
4028c2ecf20Sopenharmony_ci	.optional = opt,	\
4038c2ecf20Sopenharmony_ci	.dom = domain
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_cistatic const struct pci_id_descr pci_dev_descr_sbridge[] = {
4068c2ecf20Sopenharmony_ci		/* Processor Home Agent */
4078c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0,   0, IMC0) },
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci		/* Memory controller */
4108c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA,    0, IMC0) },
4118c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS,   0, IMC0) },
4128c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0,  0, IMC0) },
4138c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1,  0, IMC0) },
4148c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2,  0, IMC0) },
4158c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3,  0, IMC0) },
4168c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO, 1, SOCK) },
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci		/* System Address Decoder */
4198c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0,      0, SOCK) },
4208c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1,      0, SOCK) },
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci		/* Broadcast Registers */
4238c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_BR,        0, SOCK) },
4248c2ecf20Sopenharmony_ci};
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci#define PCI_ID_TABLE_ENTRY(A, N, M, T) {	\
4278c2ecf20Sopenharmony_ci	.descr = A,			\
4288c2ecf20Sopenharmony_ci	.n_devs_per_imc = N,	\
4298c2ecf20Sopenharmony_ci	.n_devs_per_sock = ARRAY_SIZE(A),	\
4308c2ecf20Sopenharmony_ci	.n_imcs_per_sock = M,	\
4318c2ecf20Sopenharmony_ci	.type = T			\
4328c2ecf20Sopenharmony_ci}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_cistatic const struct pci_id_table pci_dev_descr_sbridge_table[] = {
4358c2ecf20Sopenharmony_ci	PCI_ID_TABLE_ENTRY(pci_dev_descr_sbridge, ARRAY_SIZE(pci_dev_descr_sbridge), 1, SANDY_BRIDGE),
4368c2ecf20Sopenharmony_ci	{0,}			/* 0 terminated list. */
4378c2ecf20Sopenharmony_ci};
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci/* This changes depending if 1HA or 2HA:
4408c2ecf20Sopenharmony_ci * 1HA:
4418c2ecf20Sopenharmony_ci *	0x0eb8 (17.0) is DDRIO0
4428c2ecf20Sopenharmony_ci * 2HA:
4438c2ecf20Sopenharmony_ci *	0x0ebc (17.4) is DDRIO0
4448c2ecf20Sopenharmony_ci */
4458c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0	0x0eb8
4468c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0	0x0ebc
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci/* pci ids */
4498c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0		0x0ea0
4508c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA		0x0ea8
4518c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS		0x0e71
4528c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0	0x0eaa
4538c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1	0x0eab
4548c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2	0x0eac
4558c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3	0x0ead
4568c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_IBRIDGE_SAD			0x0ec8
4578c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_IBRIDGE_BR0			0x0ec9
4588c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_IBRIDGE_BR1			0x0eca
4598c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1		0x0e60
4608c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA		0x0e68
4618c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS		0x0e79
4628c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0	0x0e6a
4638c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1	0x0e6b
4648c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD2	0x0e6c
4658c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD3	0x0e6d
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_cistatic const struct pci_id_descr pci_dev_descr_ibridge[] = {
4688c2ecf20Sopenharmony_ci		/* Processor Home Agent */
4698c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0,        0, IMC0) },
4708c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1,        1, IMC1) },
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci		/* Memory controller */
4738c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA,     0, IMC0) },
4748c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS,    0, IMC0) },
4758c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0,   0, IMC0) },
4768c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1,   0, IMC0) },
4778c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2,   0, IMC0) },
4788c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3,   0, IMC0) },
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci		/* Optional, mode 2HA */
4818c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA,     1, IMC1) },
4828c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS,    1, IMC1) },
4838c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0,   1, IMC1) },
4848c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1,   1, IMC1) },
4858c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD2,   1, IMC1) },
4868c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD3,   1, IMC1) },
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0, 1, SOCK) },
4898c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0, 1, SOCK) },
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci		/* System Address Decoder */
4928c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_SAD,            0, SOCK) },
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci		/* Broadcast Registers */
4958c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_BR0,            1, SOCK) },
4968c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_BR1,            0, SOCK) },
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci};
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_cistatic const struct pci_id_table pci_dev_descr_ibridge_table[] = {
5018c2ecf20Sopenharmony_ci	PCI_ID_TABLE_ENTRY(pci_dev_descr_ibridge, 12, 2, IVY_BRIDGE),
5028c2ecf20Sopenharmony_ci	{0,}			/* 0 terminated list. */
5038c2ecf20Sopenharmony_ci};
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci/* Haswell support */
5068c2ecf20Sopenharmony_ci/* EN processor:
5078c2ecf20Sopenharmony_ci *	- 1 IMC
5088c2ecf20Sopenharmony_ci *	- 3 DDR3 channels, 2 DPC per channel
5098c2ecf20Sopenharmony_ci * EP processor:
5108c2ecf20Sopenharmony_ci *	- 1 or 2 IMC
5118c2ecf20Sopenharmony_ci *	- 4 DDR4 channels, 3 DPC per channel
5128c2ecf20Sopenharmony_ci * EP 4S processor:
5138c2ecf20Sopenharmony_ci *	- 2 IMC
5148c2ecf20Sopenharmony_ci *	- 4 DDR4 channels, 3 DPC per channel
5158c2ecf20Sopenharmony_ci * EX processor:
5168c2ecf20Sopenharmony_ci *	- 2 IMC
5178c2ecf20Sopenharmony_ci *	- each IMC interfaces with a SMI 2 channel
5188c2ecf20Sopenharmony_ci *	- each SMI channel interfaces with a scalable memory buffer
5198c2ecf20Sopenharmony_ci *	- each scalable memory buffer supports 4 DDR3/DDR4 channels, 3 DPC
5208c2ecf20Sopenharmony_ci */
5218c2ecf20Sopenharmony_ci#define HASWELL_DDRCRCLKCONTROLS 0xa10 /* Ditto on Broadwell */
5228c2ecf20Sopenharmony_ci#define HASWELL_HASYSDEFEATURE2 0x84
5238c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_VTD_MISC 0x2f28
5248c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0	0x2fa0
5258c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1	0x2f60
5268c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA	0x2fa8
5278c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TM	0x2f71
5288c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA	0x2f68
5298c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TM	0x2f79
5308c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD0 0x2ffc
5318c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD1 0x2ffd
5328c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD0 0x2faa
5338c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD1 0x2fab
5348c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD2 0x2fac
5358c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3 0x2fad
5368c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD0 0x2f6a
5378c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD1 0x2f6b
5388c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD2 0x2f6c
5398c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD3 0x2f6d
5408c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0 0x2fbd
5418c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO1 0x2fbf
5428c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO2 0x2fb9
5438c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO3 0x2fbb
5448c2ecf20Sopenharmony_cistatic const struct pci_id_descr pci_dev_descr_haswell[] = {
5458c2ecf20Sopenharmony_ci	/* first item must be the HA */
5468c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0,      0, IMC0) },
5478c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1,      1, IMC1) },
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA,   0, IMC0) },
5508c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TM,   0, IMC0) },
5518c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD0, 0, IMC0) },
5528c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD1, 0, IMC0) },
5538c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD2, 1, IMC0) },
5548c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3, 1, IMC0) },
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA,   1, IMC1) },
5578c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TM,   1, IMC1) },
5588c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD0, 1, IMC1) },
5598c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD1, 1, IMC1) },
5608c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD2, 1, IMC1) },
5618c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD3, 1, IMC1) },
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD0, 0, SOCK) },
5648c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD1, 0, SOCK) },
5658c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0,   1, SOCK) },
5668c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO1,   1, SOCK) },
5678c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO2,   1, SOCK) },
5688c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO3,   1, SOCK) },
5698c2ecf20Sopenharmony_ci};
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_cistatic const struct pci_id_table pci_dev_descr_haswell_table[] = {
5728c2ecf20Sopenharmony_ci	PCI_ID_TABLE_ENTRY(pci_dev_descr_haswell, 13, 2, HASWELL),
5738c2ecf20Sopenharmony_ci	{0,}			/* 0 terminated list. */
5748c2ecf20Sopenharmony_ci};
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci/* Knight's Landing Support */
5778c2ecf20Sopenharmony_ci/*
5788c2ecf20Sopenharmony_ci * KNL's memory channels are swizzled between memory controllers.
5798c2ecf20Sopenharmony_ci * MC0 is mapped to CH3,4,5 and MC1 is mapped to CH0,1,2
5808c2ecf20Sopenharmony_ci */
5818c2ecf20Sopenharmony_ci#define knl_channel_remap(mc, chan) ((mc) ? (chan) : (chan) + 3)
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci/* Memory controller, TAD tables, error injection - 2-8-0, 2-9-0 (2 of these) */
5848c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_KNL_IMC_MC       0x7840
5858c2ecf20Sopenharmony_ci/* DRAM channel stuff; bank addrs, dimmmtr, etc.. 2-8-2 - 2-9-4 (6 of these) */
5868c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_KNL_IMC_CHAN     0x7843
5878c2ecf20Sopenharmony_ci/* kdrwdbu TAD limits/offsets, MCMTR - 2-10-1, 2-11-1 (2 of these) */
5888c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_KNL_IMC_TA       0x7844
5898c2ecf20Sopenharmony_ci/* CHA broadcast registers, dram rules - 1-29-0 (1 of these) */
5908c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0     0x782a
5918c2ecf20Sopenharmony_ci/* SAD target - 1-29-1 (1 of these) */
5928c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_KNL_IMC_SAD1     0x782b
5938c2ecf20Sopenharmony_ci/* Caching / Home Agent */
5948c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_KNL_IMC_CHA      0x782c
5958c2ecf20Sopenharmony_ci/* Device with TOLM and TOHM, 0-5-0 (1 of these) */
5968c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_KNL_IMC_TOLHM    0x7810
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci/*
5998c2ecf20Sopenharmony_ci * KNL differs from SB, IB, and Haswell in that it has multiple
6008c2ecf20Sopenharmony_ci * instances of the same device with the same device ID, so we handle that
6018c2ecf20Sopenharmony_ci * by creating as many copies in the table as we expect to find.
6028c2ecf20Sopenharmony_ci * (Like device ID must be grouped together.)
6038c2ecf20Sopenharmony_ci */
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_cistatic const struct pci_id_descr pci_dev_descr_knl[] = {
6068c2ecf20Sopenharmony_ci	[0 ... 1]   = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_MC,    0, IMC0)},
6078c2ecf20Sopenharmony_ci	[2 ... 7]   = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_CHAN,  0, IMC0) },
6088c2ecf20Sopenharmony_ci	[8]	    = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_TA,    0, IMC0) },
6098c2ecf20Sopenharmony_ci	[9]	    = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_TOLHM, 0, IMC0) },
6108c2ecf20Sopenharmony_ci	[10]	    = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0,  0, SOCK) },
6118c2ecf20Sopenharmony_ci	[11]	    = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_SAD1,  0, SOCK) },
6128c2ecf20Sopenharmony_ci	[12 ... 49] = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_CHA,   0, SOCK) },
6138c2ecf20Sopenharmony_ci};
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_cistatic const struct pci_id_table pci_dev_descr_knl_table[] = {
6168c2ecf20Sopenharmony_ci	PCI_ID_TABLE_ENTRY(pci_dev_descr_knl, ARRAY_SIZE(pci_dev_descr_knl), 1, KNIGHTS_LANDING),
6178c2ecf20Sopenharmony_ci	{0,}
6188c2ecf20Sopenharmony_ci};
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci/*
6218c2ecf20Sopenharmony_ci * Broadwell support
6228c2ecf20Sopenharmony_ci *
6238c2ecf20Sopenharmony_ci * DE processor:
6248c2ecf20Sopenharmony_ci *	- 1 IMC
6258c2ecf20Sopenharmony_ci *	- 2 DDR3 channels, 2 DPC per channel
6268c2ecf20Sopenharmony_ci * EP processor:
6278c2ecf20Sopenharmony_ci *	- 1 or 2 IMC
6288c2ecf20Sopenharmony_ci *	- 4 DDR4 channels, 3 DPC per channel
6298c2ecf20Sopenharmony_ci * EP 4S processor:
6308c2ecf20Sopenharmony_ci *	- 2 IMC
6318c2ecf20Sopenharmony_ci *	- 4 DDR4 channels, 3 DPC per channel
6328c2ecf20Sopenharmony_ci * EX processor:
6338c2ecf20Sopenharmony_ci *	- 2 IMC
6348c2ecf20Sopenharmony_ci *	- each IMC interfaces with a SMI 2 channel
6358c2ecf20Sopenharmony_ci *	- each SMI channel interfaces with a scalable memory buffer
6368c2ecf20Sopenharmony_ci *	- each scalable memory buffer supports 4 DDR3/DDR4 channels, 3 DPC
6378c2ecf20Sopenharmony_ci */
6388c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_VTD_MISC 0x6f28
6398c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0	0x6fa0
6408c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1	0x6f60
6418c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA	0x6fa8
6428c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TM	0x6f71
6438c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TA	0x6f68
6448c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TM	0x6f79
6458c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD0 0x6ffc
6468c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD1 0x6ffd
6478c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD0 0x6faa
6488c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD1 0x6fab
6498c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD2 0x6fac
6508c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD3 0x6fad
6518c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD0 0x6f6a
6528c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD1 0x6f6b
6538c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD2 0x6f6c
6548c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD3 0x6f6d
6558c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_DDRIO0 0x6faf
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_cistatic const struct pci_id_descr pci_dev_descr_broadwell[] = {
6588c2ecf20Sopenharmony_ci	/* first item must be the HA */
6598c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0,      0, IMC0) },
6608c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1,      1, IMC1) },
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA,   0, IMC0) },
6638c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TM,   0, IMC0) },
6648c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD0, 0, IMC0) },
6658c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD1, 0, IMC0) },
6668c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD2, 1, IMC0) },
6678c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD3, 1, IMC0) },
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TA,   1, IMC1) },
6708c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TM,   1, IMC1) },
6718c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD0, 1, IMC1) },
6728c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD1, 1, IMC1) },
6738c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD2, 1, IMC1) },
6748c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD3, 1, IMC1) },
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD0, 0, SOCK) },
6778c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD1, 0, SOCK) },
6788c2ecf20Sopenharmony_ci	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_DDRIO0,   1, SOCK) },
6798c2ecf20Sopenharmony_ci};
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_cistatic const struct pci_id_table pci_dev_descr_broadwell_table[] = {
6828c2ecf20Sopenharmony_ci	PCI_ID_TABLE_ENTRY(pci_dev_descr_broadwell, 10, 2, BROADWELL),
6838c2ecf20Sopenharmony_ci	{0,}			/* 0 terminated list. */
6848c2ecf20Sopenharmony_ci};
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci/****************************************************************************
6888c2ecf20Sopenharmony_ci			Ancillary status routines
6898c2ecf20Sopenharmony_ci ****************************************************************************/
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_cistatic inline int numrank(enum type type, u32 mtr)
6928c2ecf20Sopenharmony_ci{
6938c2ecf20Sopenharmony_ci	int ranks = (1 << RANK_CNT_BITS(mtr));
6948c2ecf20Sopenharmony_ci	int max = 4;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	if (type == HASWELL || type == BROADWELL || type == KNIGHTS_LANDING)
6978c2ecf20Sopenharmony_ci		max = 8;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	if (ranks > max) {
7008c2ecf20Sopenharmony_ci		edac_dbg(0, "Invalid number of ranks: %d (max = %i) raw value = %x (%04x)\n",
7018c2ecf20Sopenharmony_ci			 ranks, max, (unsigned int)RANK_CNT_BITS(mtr), mtr);
7028c2ecf20Sopenharmony_ci		return -EINVAL;
7038c2ecf20Sopenharmony_ci	}
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	return ranks;
7068c2ecf20Sopenharmony_ci}
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_cistatic inline int numrow(u32 mtr)
7098c2ecf20Sopenharmony_ci{
7108c2ecf20Sopenharmony_ci	int rows = (RANK_WIDTH_BITS(mtr) + 12);
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	if (rows < 13 || rows > 18) {
7138c2ecf20Sopenharmony_ci		edac_dbg(0, "Invalid number of rows: %d (should be between 14 and 17) raw value = %x (%04x)\n",
7148c2ecf20Sopenharmony_ci			 rows, (unsigned int)RANK_WIDTH_BITS(mtr), mtr);
7158c2ecf20Sopenharmony_ci		return -EINVAL;
7168c2ecf20Sopenharmony_ci	}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	return 1 << rows;
7198c2ecf20Sopenharmony_ci}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_cistatic inline int numcol(u32 mtr)
7228c2ecf20Sopenharmony_ci{
7238c2ecf20Sopenharmony_ci	int cols = (COL_WIDTH_BITS(mtr) + 10);
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	if (cols > 12) {
7268c2ecf20Sopenharmony_ci		edac_dbg(0, "Invalid number of cols: %d (max = 4) raw value = %x (%04x)\n",
7278c2ecf20Sopenharmony_ci			 cols, (unsigned int)COL_WIDTH_BITS(mtr), mtr);
7288c2ecf20Sopenharmony_ci		return -EINVAL;
7298c2ecf20Sopenharmony_ci	}
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	return 1 << cols;
7328c2ecf20Sopenharmony_ci}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_cistatic struct sbridge_dev *get_sbridge_dev(int seg, u8 bus, enum domain dom,
7358c2ecf20Sopenharmony_ci					   int multi_bus,
7368c2ecf20Sopenharmony_ci					   struct sbridge_dev *prev)
7378c2ecf20Sopenharmony_ci{
7388c2ecf20Sopenharmony_ci	struct sbridge_dev *sbridge_dev;
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	/*
7418c2ecf20Sopenharmony_ci	 * If we have devices scattered across several busses that pertain
7428c2ecf20Sopenharmony_ci	 * to the same memory controller, we'll lump them all together.
7438c2ecf20Sopenharmony_ci	 */
7448c2ecf20Sopenharmony_ci	if (multi_bus) {
7458c2ecf20Sopenharmony_ci		return list_first_entry_or_null(&sbridge_edac_list,
7468c2ecf20Sopenharmony_ci				struct sbridge_dev, list);
7478c2ecf20Sopenharmony_ci	}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	sbridge_dev = list_entry(prev ? prev->list.next
7508c2ecf20Sopenharmony_ci				      : sbridge_edac_list.next, struct sbridge_dev, list);
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	list_for_each_entry_from(sbridge_dev, &sbridge_edac_list, list) {
7538c2ecf20Sopenharmony_ci		if ((sbridge_dev->seg == seg) && (sbridge_dev->bus == bus) &&
7548c2ecf20Sopenharmony_ci				(dom == SOCK || dom == sbridge_dev->dom))
7558c2ecf20Sopenharmony_ci			return sbridge_dev;
7568c2ecf20Sopenharmony_ci	}
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	return NULL;
7598c2ecf20Sopenharmony_ci}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_cistatic struct sbridge_dev *alloc_sbridge_dev(int seg, u8 bus, enum domain dom,
7628c2ecf20Sopenharmony_ci					     const struct pci_id_table *table)
7638c2ecf20Sopenharmony_ci{
7648c2ecf20Sopenharmony_ci	struct sbridge_dev *sbridge_dev;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	sbridge_dev = kzalloc(sizeof(*sbridge_dev), GFP_KERNEL);
7678c2ecf20Sopenharmony_ci	if (!sbridge_dev)
7688c2ecf20Sopenharmony_ci		return NULL;
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	sbridge_dev->pdev = kcalloc(table->n_devs_per_imc,
7718c2ecf20Sopenharmony_ci				    sizeof(*sbridge_dev->pdev),
7728c2ecf20Sopenharmony_ci				    GFP_KERNEL);
7738c2ecf20Sopenharmony_ci	if (!sbridge_dev->pdev) {
7748c2ecf20Sopenharmony_ci		kfree(sbridge_dev);
7758c2ecf20Sopenharmony_ci		return NULL;
7768c2ecf20Sopenharmony_ci	}
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	sbridge_dev->seg = seg;
7798c2ecf20Sopenharmony_ci	sbridge_dev->bus = bus;
7808c2ecf20Sopenharmony_ci	sbridge_dev->dom = dom;
7818c2ecf20Sopenharmony_ci	sbridge_dev->n_devs = table->n_devs_per_imc;
7828c2ecf20Sopenharmony_ci	list_add_tail(&sbridge_dev->list, &sbridge_edac_list);
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	return sbridge_dev;
7858c2ecf20Sopenharmony_ci}
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_cistatic void free_sbridge_dev(struct sbridge_dev *sbridge_dev)
7888c2ecf20Sopenharmony_ci{
7898c2ecf20Sopenharmony_ci	list_del(&sbridge_dev->list);
7908c2ecf20Sopenharmony_ci	kfree(sbridge_dev->pdev);
7918c2ecf20Sopenharmony_ci	kfree(sbridge_dev);
7928c2ecf20Sopenharmony_ci}
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_cistatic u64 sbridge_get_tolm(struct sbridge_pvt *pvt)
7958c2ecf20Sopenharmony_ci{
7968c2ecf20Sopenharmony_ci	u32 reg;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	/* Address range is 32:28 */
7998c2ecf20Sopenharmony_ci	pci_read_config_dword(pvt->pci_sad1, TOLM, &reg);
8008c2ecf20Sopenharmony_ci	return GET_TOLM(reg);
8018c2ecf20Sopenharmony_ci}
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_cistatic u64 sbridge_get_tohm(struct sbridge_pvt *pvt)
8048c2ecf20Sopenharmony_ci{
8058c2ecf20Sopenharmony_ci	u32 reg;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	pci_read_config_dword(pvt->pci_sad1, TOHM, &reg);
8088c2ecf20Sopenharmony_ci	return GET_TOHM(reg);
8098c2ecf20Sopenharmony_ci}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_cistatic u64 ibridge_get_tolm(struct sbridge_pvt *pvt)
8128c2ecf20Sopenharmony_ci{
8138c2ecf20Sopenharmony_ci	u32 reg;
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	pci_read_config_dword(pvt->pci_br1, TOLM, &reg);
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	return GET_TOLM(reg);
8188c2ecf20Sopenharmony_ci}
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_cistatic u64 ibridge_get_tohm(struct sbridge_pvt *pvt)
8218c2ecf20Sopenharmony_ci{
8228c2ecf20Sopenharmony_ci	u32 reg;
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	pci_read_config_dword(pvt->pci_br1, TOHM, &reg);
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	return GET_TOHM(reg);
8278c2ecf20Sopenharmony_ci}
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_cistatic u64 rir_limit(u32 reg)
8308c2ecf20Sopenharmony_ci{
8318c2ecf20Sopenharmony_ci	return ((u64)GET_BITFIELD(reg,  1, 10) << 29) | 0x1fffffff;
8328c2ecf20Sopenharmony_ci}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_cistatic u64 sad_limit(u32 reg)
8358c2ecf20Sopenharmony_ci{
8368c2ecf20Sopenharmony_ci	return (GET_BITFIELD(reg, 6, 25) << 26) | 0x3ffffff;
8378c2ecf20Sopenharmony_ci}
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_cistatic u32 interleave_mode(u32 reg)
8408c2ecf20Sopenharmony_ci{
8418c2ecf20Sopenharmony_ci	return GET_BITFIELD(reg, 1, 1);
8428c2ecf20Sopenharmony_ci}
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_cistatic u32 dram_attr(u32 reg)
8458c2ecf20Sopenharmony_ci{
8468c2ecf20Sopenharmony_ci	return GET_BITFIELD(reg, 2, 3);
8478c2ecf20Sopenharmony_ci}
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_cistatic u64 knl_sad_limit(u32 reg)
8508c2ecf20Sopenharmony_ci{
8518c2ecf20Sopenharmony_ci	return (GET_BITFIELD(reg, 7, 26) << 26) | 0x3ffffff;
8528c2ecf20Sopenharmony_ci}
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_cistatic u32 knl_interleave_mode(u32 reg)
8558c2ecf20Sopenharmony_ci{
8568c2ecf20Sopenharmony_ci	return GET_BITFIELD(reg, 1, 2);
8578c2ecf20Sopenharmony_ci}
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_cistatic const char * const knl_intlv_mode[] = {
8608c2ecf20Sopenharmony_ci	"[8:6]", "[10:8]", "[14:12]", "[32:30]"
8618c2ecf20Sopenharmony_ci};
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_cistatic const char *get_intlv_mode_str(u32 reg, enum type t)
8648c2ecf20Sopenharmony_ci{
8658c2ecf20Sopenharmony_ci	if (t == KNIGHTS_LANDING)
8668c2ecf20Sopenharmony_ci		return knl_intlv_mode[knl_interleave_mode(reg)];
8678c2ecf20Sopenharmony_ci	else
8688c2ecf20Sopenharmony_ci		return interleave_mode(reg) ? "[8:6]" : "[8:6]XOR[18:16]";
8698c2ecf20Sopenharmony_ci}
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_cistatic u32 dram_attr_knl(u32 reg)
8728c2ecf20Sopenharmony_ci{
8738c2ecf20Sopenharmony_ci	return GET_BITFIELD(reg, 3, 4);
8748c2ecf20Sopenharmony_ci}
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_cistatic enum mem_type get_memory_type(struct sbridge_pvt *pvt)
8788c2ecf20Sopenharmony_ci{
8798c2ecf20Sopenharmony_ci	u32 reg;
8808c2ecf20Sopenharmony_ci	enum mem_type mtype;
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	if (pvt->pci_ddrio) {
8838c2ecf20Sopenharmony_ci		pci_read_config_dword(pvt->pci_ddrio, pvt->info.rankcfgr,
8848c2ecf20Sopenharmony_ci				      &reg);
8858c2ecf20Sopenharmony_ci		if (GET_BITFIELD(reg, 11, 11))
8868c2ecf20Sopenharmony_ci			/* FIXME: Can also be LRDIMM */
8878c2ecf20Sopenharmony_ci			mtype = MEM_RDDR3;
8888c2ecf20Sopenharmony_ci		else
8898c2ecf20Sopenharmony_ci			mtype = MEM_DDR3;
8908c2ecf20Sopenharmony_ci	} else
8918c2ecf20Sopenharmony_ci		mtype = MEM_UNKNOWN;
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	return mtype;
8948c2ecf20Sopenharmony_ci}
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_cistatic enum mem_type haswell_get_memory_type(struct sbridge_pvt *pvt)
8978c2ecf20Sopenharmony_ci{
8988c2ecf20Sopenharmony_ci	u32 reg;
8998c2ecf20Sopenharmony_ci	bool registered = false;
9008c2ecf20Sopenharmony_ci	enum mem_type mtype = MEM_UNKNOWN;
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	if (!pvt->pci_ddrio)
9038c2ecf20Sopenharmony_ci		goto out;
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	pci_read_config_dword(pvt->pci_ddrio,
9068c2ecf20Sopenharmony_ci			      HASWELL_DDRCRCLKCONTROLS, &reg);
9078c2ecf20Sopenharmony_ci	/* Is_Rdimm */
9088c2ecf20Sopenharmony_ci	if (GET_BITFIELD(reg, 16, 16))
9098c2ecf20Sopenharmony_ci		registered = true;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	pci_read_config_dword(pvt->pci_ta, MCMTR, &reg);
9128c2ecf20Sopenharmony_ci	if (GET_BITFIELD(reg, 14, 14)) {
9138c2ecf20Sopenharmony_ci		if (registered)
9148c2ecf20Sopenharmony_ci			mtype = MEM_RDDR4;
9158c2ecf20Sopenharmony_ci		else
9168c2ecf20Sopenharmony_ci			mtype = MEM_DDR4;
9178c2ecf20Sopenharmony_ci	} else {
9188c2ecf20Sopenharmony_ci		if (registered)
9198c2ecf20Sopenharmony_ci			mtype = MEM_RDDR3;
9208c2ecf20Sopenharmony_ci		else
9218c2ecf20Sopenharmony_ci			mtype = MEM_DDR3;
9228c2ecf20Sopenharmony_ci	}
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ciout:
9258c2ecf20Sopenharmony_ci	return mtype;
9268c2ecf20Sopenharmony_ci}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_cistatic enum dev_type knl_get_width(struct sbridge_pvt *pvt, u32 mtr)
9298c2ecf20Sopenharmony_ci{
9308c2ecf20Sopenharmony_ci	/* for KNL value is fixed */
9318c2ecf20Sopenharmony_ci	return DEV_X16;
9328c2ecf20Sopenharmony_ci}
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_cistatic enum dev_type sbridge_get_width(struct sbridge_pvt *pvt, u32 mtr)
9358c2ecf20Sopenharmony_ci{
9368c2ecf20Sopenharmony_ci	/* there's no way to figure out */
9378c2ecf20Sopenharmony_ci	return DEV_UNKNOWN;
9388c2ecf20Sopenharmony_ci}
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_cistatic enum dev_type __ibridge_get_width(u32 mtr)
9418c2ecf20Sopenharmony_ci{
9428c2ecf20Sopenharmony_ci	enum dev_type type = DEV_UNKNOWN;
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci	switch (mtr) {
9458c2ecf20Sopenharmony_ci	case 2:
9468c2ecf20Sopenharmony_ci		type = DEV_X16;
9478c2ecf20Sopenharmony_ci		break;
9488c2ecf20Sopenharmony_ci	case 1:
9498c2ecf20Sopenharmony_ci		type = DEV_X8;
9508c2ecf20Sopenharmony_ci		break;
9518c2ecf20Sopenharmony_ci	case 0:
9528c2ecf20Sopenharmony_ci		type = DEV_X4;
9538c2ecf20Sopenharmony_ci		break;
9548c2ecf20Sopenharmony_ci	}
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	return type;
9578c2ecf20Sopenharmony_ci}
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_cistatic enum dev_type ibridge_get_width(struct sbridge_pvt *pvt, u32 mtr)
9608c2ecf20Sopenharmony_ci{
9618c2ecf20Sopenharmony_ci	/*
9628c2ecf20Sopenharmony_ci	 * ddr3_width on the documentation but also valid for DDR4 on
9638c2ecf20Sopenharmony_ci	 * Haswell
9648c2ecf20Sopenharmony_ci	 */
9658c2ecf20Sopenharmony_ci	return __ibridge_get_width(GET_BITFIELD(mtr, 7, 8));
9668c2ecf20Sopenharmony_ci}
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_cistatic enum dev_type broadwell_get_width(struct sbridge_pvt *pvt, u32 mtr)
9698c2ecf20Sopenharmony_ci{
9708c2ecf20Sopenharmony_ci	/* ddr3_width on the documentation but also valid for DDR4 */
9718c2ecf20Sopenharmony_ci	return __ibridge_get_width(GET_BITFIELD(mtr, 8, 9));
9728c2ecf20Sopenharmony_ci}
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_cistatic enum mem_type knl_get_memory_type(struct sbridge_pvt *pvt)
9758c2ecf20Sopenharmony_ci{
9768c2ecf20Sopenharmony_ci	/* DDR4 RDIMMS and LRDIMMS are supported */
9778c2ecf20Sopenharmony_ci	return MEM_RDDR4;
9788c2ecf20Sopenharmony_ci}
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_cistatic u8 get_node_id(struct sbridge_pvt *pvt)
9818c2ecf20Sopenharmony_ci{
9828c2ecf20Sopenharmony_ci	u32 reg;
9838c2ecf20Sopenharmony_ci	pci_read_config_dword(pvt->pci_br0, SAD_CONTROL, &reg);
9848c2ecf20Sopenharmony_ci	return GET_BITFIELD(reg, 0, 2);
9858c2ecf20Sopenharmony_ci}
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_cistatic u8 haswell_get_node_id(struct sbridge_pvt *pvt)
9888c2ecf20Sopenharmony_ci{
9898c2ecf20Sopenharmony_ci	u32 reg;
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	pci_read_config_dword(pvt->pci_sad1, SAD_CONTROL, &reg);
9928c2ecf20Sopenharmony_ci	return GET_BITFIELD(reg, 0, 3);
9938c2ecf20Sopenharmony_ci}
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_cistatic u8 knl_get_node_id(struct sbridge_pvt *pvt)
9968c2ecf20Sopenharmony_ci{
9978c2ecf20Sopenharmony_ci	u32 reg;
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	pci_read_config_dword(pvt->pci_sad1, SAD_CONTROL, &reg);
10008c2ecf20Sopenharmony_ci	return GET_BITFIELD(reg, 0, 2);
10018c2ecf20Sopenharmony_ci}
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci/*
10048c2ecf20Sopenharmony_ci * Use the reporting bank number to determine which memory
10058c2ecf20Sopenharmony_ci * controller (also known as "ha" for "home agent"). Sandy
10068c2ecf20Sopenharmony_ci * Bridge only has one memory controller per socket, so the
10078c2ecf20Sopenharmony_ci * answer is always zero.
10088c2ecf20Sopenharmony_ci */
10098c2ecf20Sopenharmony_cistatic u8 sbridge_get_ha(u8 bank)
10108c2ecf20Sopenharmony_ci{
10118c2ecf20Sopenharmony_ci	return 0;
10128c2ecf20Sopenharmony_ci}
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci/*
10158c2ecf20Sopenharmony_ci * On Ivy Bridge, Haswell and Broadwell the error may be in a
10168c2ecf20Sopenharmony_ci * home agent bank (7, 8), or one of the per-channel memory
10178c2ecf20Sopenharmony_ci * controller banks (9 .. 16).
10188c2ecf20Sopenharmony_ci */
10198c2ecf20Sopenharmony_cistatic u8 ibridge_get_ha(u8 bank)
10208c2ecf20Sopenharmony_ci{
10218c2ecf20Sopenharmony_ci	switch (bank) {
10228c2ecf20Sopenharmony_ci	case 7 ... 8:
10238c2ecf20Sopenharmony_ci		return bank - 7;
10248c2ecf20Sopenharmony_ci	case 9 ... 16:
10258c2ecf20Sopenharmony_ci		return (bank - 9) / 4;
10268c2ecf20Sopenharmony_ci	default:
10278c2ecf20Sopenharmony_ci		return 0xff;
10288c2ecf20Sopenharmony_ci	}
10298c2ecf20Sopenharmony_ci}
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci/* Not used, but included for safety/symmetry */
10328c2ecf20Sopenharmony_cistatic u8 knl_get_ha(u8 bank)
10338c2ecf20Sopenharmony_ci{
10348c2ecf20Sopenharmony_ci	return 0xff;
10358c2ecf20Sopenharmony_ci}
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_cistatic u64 haswell_get_tolm(struct sbridge_pvt *pvt)
10388c2ecf20Sopenharmony_ci{
10398c2ecf20Sopenharmony_ci	u32 reg;
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	pci_read_config_dword(pvt->info.pci_vtd, HASWELL_TOLM, &reg);
10428c2ecf20Sopenharmony_ci	return (GET_BITFIELD(reg, 26, 31) << 26) | 0x3ffffff;
10438c2ecf20Sopenharmony_ci}
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_cistatic u64 haswell_get_tohm(struct sbridge_pvt *pvt)
10468c2ecf20Sopenharmony_ci{
10478c2ecf20Sopenharmony_ci	u64 rc;
10488c2ecf20Sopenharmony_ci	u32 reg;
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	pci_read_config_dword(pvt->info.pci_vtd, HASWELL_TOHM_0, &reg);
10518c2ecf20Sopenharmony_ci	rc = GET_BITFIELD(reg, 26, 31);
10528c2ecf20Sopenharmony_ci	pci_read_config_dword(pvt->info.pci_vtd, HASWELL_TOHM_1, &reg);
10538c2ecf20Sopenharmony_ci	rc = ((reg << 6) | rc) << 26;
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	return rc | 0x3ffffff;
10568c2ecf20Sopenharmony_ci}
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_cistatic u64 knl_get_tolm(struct sbridge_pvt *pvt)
10598c2ecf20Sopenharmony_ci{
10608c2ecf20Sopenharmony_ci	u32 reg;
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	pci_read_config_dword(pvt->knl.pci_mc_info, KNL_TOLM, &reg);
10638c2ecf20Sopenharmony_ci	return (GET_BITFIELD(reg, 26, 31) << 26) | 0x3ffffff;
10648c2ecf20Sopenharmony_ci}
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_cistatic u64 knl_get_tohm(struct sbridge_pvt *pvt)
10678c2ecf20Sopenharmony_ci{
10688c2ecf20Sopenharmony_ci	u64 rc;
10698c2ecf20Sopenharmony_ci	u32 reg_lo, reg_hi;
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	pci_read_config_dword(pvt->knl.pci_mc_info, KNL_TOHM_0, &reg_lo);
10728c2ecf20Sopenharmony_ci	pci_read_config_dword(pvt->knl.pci_mc_info, KNL_TOHM_1, &reg_hi);
10738c2ecf20Sopenharmony_ci	rc = ((u64)reg_hi << 32) | reg_lo;
10748c2ecf20Sopenharmony_ci	return rc | 0x3ffffff;
10758c2ecf20Sopenharmony_ci}
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_cistatic u64 haswell_rir_limit(u32 reg)
10798c2ecf20Sopenharmony_ci{
10808c2ecf20Sopenharmony_ci	return (((u64)GET_BITFIELD(reg,  1, 11) + 1) << 29) - 1;
10818c2ecf20Sopenharmony_ci}
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_cistatic inline u8 sad_pkg_socket(u8 pkg)
10848c2ecf20Sopenharmony_ci{
10858c2ecf20Sopenharmony_ci	/* on Ivy Bridge, nodeID is SASS, where A is HA and S is node id */
10868c2ecf20Sopenharmony_ci	return ((pkg >> 3) << 2) | (pkg & 0x3);
10878c2ecf20Sopenharmony_ci}
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_cistatic inline u8 sad_pkg_ha(u8 pkg)
10908c2ecf20Sopenharmony_ci{
10918c2ecf20Sopenharmony_ci	return (pkg >> 2) & 0x1;
10928c2ecf20Sopenharmony_ci}
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_cistatic int haswell_chan_hash(int idx, u64 addr)
10958c2ecf20Sopenharmony_ci{
10968c2ecf20Sopenharmony_ci	int i;
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	/*
10998c2ecf20Sopenharmony_ci	 * XOR even bits from 12:26 to bit0 of idx,
11008c2ecf20Sopenharmony_ci	 *     odd bits from 13:27 to bit1
11018c2ecf20Sopenharmony_ci	 */
11028c2ecf20Sopenharmony_ci	for (i = 12; i < 28; i += 2)
11038c2ecf20Sopenharmony_ci		idx ^= (addr >> i) & 3;
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	return idx;
11068c2ecf20Sopenharmony_ci}
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci/* Low bits of TAD limit, and some metadata. */
11098c2ecf20Sopenharmony_cistatic const u32 knl_tad_dram_limit_lo[] = {
11108c2ecf20Sopenharmony_ci	0x400, 0x500, 0x600, 0x700,
11118c2ecf20Sopenharmony_ci	0x800, 0x900, 0xa00, 0xb00,
11128c2ecf20Sopenharmony_ci};
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci/* Low bits of TAD offset. */
11158c2ecf20Sopenharmony_cistatic const u32 knl_tad_dram_offset_lo[] = {
11168c2ecf20Sopenharmony_ci	0x404, 0x504, 0x604, 0x704,
11178c2ecf20Sopenharmony_ci	0x804, 0x904, 0xa04, 0xb04,
11188c2ecf20Sopenharmony_ci};
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci/* High 16 bits of TAD limit and offset. */
11218c2ecf20Sopenharmony_cistatic const u32 knl_tad_dram_hi[] = {
11228c2ecf20Sopenharmony_ci	0x408, 0x508, 0x608, 0x708,
11238c2ecf20Sopenharmony_ci	0x808, 0x908, 0xa08, 0xb08,
11248c2ecf20Sopenharmony_ci};
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci/* Number of ways a tad entry is interleaved. */
11278c2ecf20Sopenharmony_cistatic const u32 knl_tad_ways[] = {
11288c2ecf20Sopenharmony_ci	8, 6, 4, 3, 2, 1,
11298c2ecf20Sopenharmony_ci};
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci/*
11328c2ecf20Sopenharmony_ci * Retrieve the n'th Target Address Decode table entry
11338c2ecf20Sopenharmony_ci * from the memory controller's TAD table.
11348c2ecf20Sopenharmony_ci *
11358c2ecf20Sopenharmony_ci * @pvt:	driver private data
11368c2ecf20Sopenharmony_ci * @entry:	which entry you want to retrieve
11378c2ecf20Sopenharmony_ci * @mc:		which memory controller (0 or 1)
11388c2ecf20Sopenharmony_ci * @offset:	output tad range offset
11398c2ecf20Sopenharmony_ci * @limit:	output address of first byte above tad range
11408c2ecf20Sopenharmony_ci * @ways:	output number of interleave ways
11418c2ecf20Sopenharmony_ci *
11428c2ecf20Sopenharmony_ci * The offset value has curious semantics.  It's a sort of running total
11438c2ecf20Sopenharmony_ci * of the sizes of all the memory regions that aren't mapped in this
11448c2ecf20Sopenharmony_ci * tad table.
11458c2ecf20Sopenharmony_ci */
11468c2ecf20Sopenharmony_cistatic int knl_get_tad(const struct sbridge_pvt *pvt,
11478c2ecf20Sopenharmony_ci		const int entry,
11488c2ecf20Sopenharmony_ci		const int mc,
11498c2ecf20Sopenharmony_ci		u64 *offset,
11508c2ecf20Sopenharmony_ci		u64 *limit,
11518c2ecf20Sopenharmony_ci		int *ways)
11528c2ecf20Sopenharmony_ci{
11538c2ecf20Sopenharmony_ci	u32 reg_limit_lo, reg_offset_lo, reg_hi;
11548c2ecf20Sopenharmony_ci	struct pci_dev *pci_mc;
11558c2ecf20Sopenharmony_ci	int way_id;
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci	switch (mc) {
11588c2ecf20Sopenharmony_ci	case 0:
11598c2ecf20Sopenharmony_ci		pci_mc = pvt->knl.pci_mc0;
11608c2ecf20Sopenharmony_ci		break;
11618c2ecf20Sopenharmony_ci	case 1:
11628c2ecf20Sopenharmony_ci		pci_mc = pvt->knl.pci_mc1;
11638c2ecf20Sopenharmony_ci		break;
11648c2ecf20Sopenharmony_ci	default:
11658c2ecf20Sopenharmony_ci		WARN_ON(1);
11668c2ecf20Sopenharmony_ci		return -EINVAL;
11678c2ecf20Sopenharmony_ci	}
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	pci_read_config_dword(pci_mc,
11708c2ecf20Sopenharmony_ci			knl_tad_dram_limit_lo[entry], &reg_limit_lo);
11718c2ecf20Sopenharmony_ci	pci_read_config_dword(pci_mc,
11728c2ecf20Sopenharmony_ci			knl_tad_dram_offset_lo[entry], &reg_offset_lo);
11738c2ecf20Sopenharmony_ci	pci_read_config_dword(pci_mc,
11748c2ecf20Sopenharmony_ci			knl_tad_dram_hi[entry], &reg_hi);
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci	/* Is this TAD entry enabled? */
11778c2ecf20Sopenharmony_ci	if (!GET_BITFIELD(reg_limit_lo, 0, 0))
11788c2ecf20Sopenharmony_ci		return -ENODEV;
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	way_id = GET_BITFIELD(reg_limit_lo, 3, 5);
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	if (way_id < ARRAY_SIZE(knl_tad_ways)) {
11838c2ecf20Sopenharmony_ci		*ways = knl_tad_ways[way_id];
11848c2ecf20Sopenharmony_ci	} else {
11858c2ecf20Sopenharmony_ci		*ways = 0;
11868c2ecf20Sopenharmony_ci		sbridge_printk(KERN_ERR,
11878c2ecf20Sopenharmony_ci				"Unexpected value %d in mc_tad_limit_lo wayness field\n",
11888c2ecf20Sopenharmony_ci				way_id);
11898c2ecf20Sopenharmony_ci		return -ENODEV;
11908c2ecf20Sopenharmony_ci	}
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_ci	/*
11938c2ecf20Sopenharmony_ci	 * The least significant 6 bits of base and limit are truncated.
11948c2ecf20Sopenharmony_ci	 * For limit, we fill the missing bits with 1s.
11958c2ecf20Sopenharmony_ci	 */
11968c2ecf20Sopenharmony_ci	*offset = ((u64) GET_BITFIELD(reg_offset_lo, 6, 31) << 6) |
11978c2ecf20Sopenharmony_ci				((u64) GET_BITFIELD(reg_hi, 0,  15) << 32);
11988c2ecf20Sopenharmony_ci	*limit = ((u64) GET_BITFIELD(reg_limit_lo,  6, 31) << 6) | 63 |
11998c2ecf20Sopenharmony_ci				((u64) GET_BITFIELD(reg_hi, 16, 31) << 32);
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci	return 0;
12028c2ecf20Sopenharmony_ci}
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci/* Determine which memory controller is responsible for a given channel. */
12058c2ecf20Sopenharmony_cistatic int knl_channel_mc(int channel)
12068c2ecf20Sopenharmony_ci{
12078c2ecf20Sopenharmony_ci	WARN_ON(channel < 0 || channel >= 6);
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci	return channel < 3 ? 1 : 0;
12108c2ecf20Sopenharmony_ci}
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci/*
12138c2ecf20Sopenharmony_ci * Get the Nth entry from EDC_ROUTE_TABLE register.
12148c2ecf20Sopenharmony_ci * (This is the per-tile mapping of logical interleave targets to
12158c2ecf20Sopenharmony_ci *  physical EDC modules.)
12168c2ecf20Sopenharmony_ci *
12178c2ecf20Sopenharmony_ci * entry 0: 0:2
12188c2ecf20Sopenharmony_ci *       1: 3:5
12198c2ecf20Sopenharmony_ci *       2: 6:8
12208c2ecf20Sopenharmony_ci *       3: 9:11
12218c2ecf20Sopenharmony_ci *       4: 12:14
12228c2ecf20Sopenharmony_ci *       5: 15:17
12238c2ecf20Sopenharmony_ci *       6: 18:20
12248c2ecf20Sopenharmony_ci *       7: 21:23
12258c2ecf20Sopenharmony_ci * reserved: 24:31
12268c2ecf20Sopenharmony_ci */
12278c2ecf20Sopenharmony_cistatic u32 knl_get_edc_route(int entry, u32 reg)
12288c2ecf20Sopenharmony_ci{
12298c2ecf20Sopenharmony_ci	WARN_ON(entry >= KNL_MAX_EDCS);
12308c2ecf20Sopenharmony_ci	return GET_BITFIELD(reg, entry*3, (entry*3)+2);
12318c2ecf20Sopenharmony_ci}
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci/*
12348c2ecf20Sopenharmony_ci * Get the Nth entry from MC_ROUTE_TABLE register.
12358c2ecf20Sopenharmony_ci * (This is the per-tile mapping of logical interleave targets to
12368c2ecf20Sopenharmony_ci *  physical DRAM channels modules.)
12378c2ecf20Sopenharmony_ci *
12388c2ecf20Sopenharmony_ci * entry 0: mc 0:2   channel 18:19
12398c2ecf20Sopenharmony_ci *       1: mc 3:5   channel 20:21
12408c2ecf20Sopenharmony_ci *       2: mc 6:8   channel 22:23
12418c2ecf20Sopenharmony_ci *       3: mc 9:11  channel 24:25
12428c2ecf20Sopenharmony_ci *       4: mc 12:14 channel 26:27
12438c2ecf20Sopenharmony_ci *       5: mc 15:17 channel 28:29
12448c2ecf20Sopenharmony_ci * reserved: 30:31
12458c2ecf20Sopenharmony_ci *
12468c2ecf20Sopenharmony_ci * Though we have 3 bits to identify the MC, we should only see
12478c2ecf20Sopenharmony_ci * the values 0 or 1.
12488c2ecf20Sopenharmony_ci */
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_cistatic u32 knl_get_mc_route(int entry, u32 reg)
12518c2ecf20Sopenharmony_ci{
12528c2ecf20Sopenharmony_ci	int mc, chan;
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	WARN_ON(entry >= KNL_MAX_CHANNELS);
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	mc = GET_BITFIELD(reg, entry*3, (entry*3)+2);
12578c2ecf20Sopenharmony_ci	chan = GET_BITFIELD(reg, (entry*2) + 18, (entry*2) + 18 + 1);
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	return knl_channel_remap(mc, chan);
12608c2ecf20Sopenharmony_ci}
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci/*
12638c2ecf20Sopenharmony_ci * Render the EDC_ROUTE register in human-readable form.
12648c2ecf20Sopenharmony_ci * Output string s should be at least KNL_MAX_EDCS*2 bytes.
12658c2ecf20Sopenharmony_ci */
12668c2ecf20Sopenharmony_cistatic void knl_show_edc_route(u32 reg, char *s)
12678c2ecf20Sopenharmony_ci{
12688c2ecf20Sopenharmony_ci	int i;
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	for (i = 0; i < KNL_MAX_EDCS; i++) {
12718c2ecf20Sopenharmony_ci		s[i*2] = knl_get_edc_route(i, reg) + '0';
12728c2ecf20Sopenharmony_ci		s[i*2+1] = '-';
12738c2ecf20Sopenharmony_ci	}
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci	s[KNL_MAX_EDCS*2 - 1] = '\0';
12768c2ecf20Sopenharmony_ci}
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci/*
12798c2ecf20Sopenharmony_ci * Render the MC_ROUTE register in human-readable form.
12808c2ecf20Sopenharmony_ci * Output string s should be at least KNL_MAX_CHANNELS*2 bytes.
12818c2ecf20Sopenharmony_ci */
12828c2ecf20Sopenharmony_cistatic void knl_show_mc_route(u32 reg, char *s)
12838c2ecf20Sopenharmony_ci{
12848c2ecf20Sopenharmony_ci	int i;
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	for (i = 0; i < KNL_MAX_CHANNELS; i++) {
12878c2ecf20Sopenharmony_ci		s[i*2] = knl_get_mc_route(i, reg) + '0';
12888c2ecf20Sopenharmony_ci		s[i*2+1] = '-';
12898c2ecf20Sopenharmony_ci	}
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci	s[KNL_MAX_CHANNELS*2 - 1] = '\0';
12928c2ecf20Sopenharmony_ci}
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci#define KNL_EDC_ROUTE 0xb8
12958c2ecf20Sopenharmony_ci#define KNL_MC_ROUTE 0xb4
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci/* Is this dram rule backed by regular DRAM in flat mode? */
12988c2ecf20Sopenharmony_ci#define KNL_EDRAM(reg) GET_BITFIELD(reg, 29, 29)
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci/* Is this dram rule cached? */
13018c2ecf20Sopenharmony_ci#define KNL_CACHEABLE(reg) GET_BITFIELD(reg, 28, 28)
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci/* Is this rule backed by edc ? */
13048c2ecf20Sopenharmony_ci#define KNL_EDRAM_ONLY(reg) GET_BITFIELD(reg, 29, 29)
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci/* Is this rule backed by DRAM, cacheable in EDRAM? */
13078c2ecf20Sopenharmony_ci#define KNL_CACHEABLE(reg) GET_BITFIELD(reg, 28, 28)
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci/* Is this rule mod3? */
13108c2ecf20Sopenharmony_ci#define KNL_MOD3(reg) GET_BITFIELD(reg, 27, 27)
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci/*
13138c2ecf20Sopenharmony_ci * Figure out how big our RAM modules are.
13148c2ecf20Sopenharmony_ci *
13158c2ecf20Sopenharmony_ci * The DIMMMTR register in KNL doesn't tell us the size of the DIMMs, so we
13168c2ecf20Sopenharmony_ci * have to figure this out from the SAD rules, interleave lists, route tables,
13178c2ecf20Sopenharmony_ci * and TAD rules.
13188c2ecf20Sopenharmony_ci *
13198c2ecf20Sopenharmony_ci * SAD rules can have holes in them (e.g. the 3G-4G hole), so we have to
13208c2ecf20Sopenharmony_ci * inspect the TAD rules to figure out how large the SAD regions really are.
13218c2ecf20Sopenharmony_ci *
13228c2ecf20Sopenharmony_ci * When we know the real size of a SAD region and how many ways it's
13238c2ecf20Sopenharmony_ci * interleaved, we know the individual contribution of each channel to
13248c2ecf20Sopenharmony_ci * TAD is size/ways.
13258c2ecf20Sopenharmony_ci *
13268c2ecf20Sopenharmony_ci * Finally, we have to check whether each channel participates in each SAD
13278c2ecf20Sopenharmony_ci * region.
13288c2ecf20Sopenharmony_ci *
13298c2ecf20Sopenharmony_ci * Fortunately, KNL only supports one DIMM per channel, so once we know how
13308c2ecf20Sopenharmony_ci * much memory the channel uses, we know the DIMM is at least that large.
13318c2ecf20Sopenharmony_ci * (The BIOS might possibly choose not to map all available memory, in which
13328c2ecf20Sopenharmony_ci * case we will underreport the size of the DIMM.)
13338c2ecf20Sopenharmony_ci *
13348c2ecf20Sopenharmony_ci * In theory, we could try to determine the EDC sizes as well, but that would
13358c2ecf20Sopenharmony_ci * only work in flat mode, not in cache mode.
13368c2ecf20Sopenharmony_ci *
13378c2ecf20Sopenharmony_ci * @mc_sizes: Output sizes of channels (must have space for KNL_MAX_CHANNELS
13388c2ecf20Sopenharmony_ci *            elements)
13398c2ecf20Sopenharmony_ci */
13408c2ecf20Sopenharmony_cistatic int knl_get_dimm_capacity(struct sbridge_pvt *pvt, u64 *mc_sizes)
13418c2ecf20Sopenharmony_ci{
13428c2ecf20Sopenharmony_ci	u64 sad_base, sad_limit = 0;
13438c2ecf20Sopenharmony_ci	u64 tad_base, tad_size, tad_limit, tad_deadspace, tad_livespace;
13448c2ecf20Sopenharmony_ci	int sad_rule = 0;
13458c2ecf20Sopenharmony_ci	int tad_rule = 0;
13468c2ecf20Sopenharmony_ci	int intrlv_ways, tad_ways;
13478c2ecf20Sopenharmony_ci	u32 first_pkg, pkg;
13488c2ecf20Sopenharmony_ci	int i;
13498c2ecf20Sopenharmony_ci	u64 sad_actual_size[2]; /* sad size accounting for holes, per mc */
13508c2ecf20Sopenharmony_ci	u32 dram_rule, interleave_reg;
13518c2ecf20Sopenharmony_ci	u32 mc_route_reg[KNL_MAX_CHAS];
13528c2ecf20Sopenharmony_ci	u32 edc_route_reg[KNL_MAX_CHAS];
13538c2ecf20Sopenharmony_ci	int edram_only;
13548c2ecf20Sopenharmony_ci	char edc_route_string[KNL_MAX_EDCS*2];
13558c2ecf20Sopenharmony_ci	char mc_route_string[KNL_MAX_CHANNELS*2];
13568c2ecf20Sopenharmony_ci	int cur_reg_start;
13578c2ecf20Sopenharmony_ci	int mc;
13588c2ecf20Sopenharmony_ci	int channel;
13598c2ecf20Sopenharmony_ci	int participants[KNL_MAX_CHANNELS];
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	for (i = 0; i < KNL_MAX_CHANNELS; i++)
13628c2ecf20Sopenharmony_ci		mc_sizes[i] = 0;
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	/* Read the EDC route table in each CHA. */
13658c2ecf20Sopenharmony_ci	cur_reg_start = 0;
13668c2ecf20Sopenharmony_ci	for (i = 0; i < KNL_MAX_CHAS; i++) {
13678c2ecf20Sopenharmony_ci		pci_read_config_dword(pvt->knl.pci_cha[i],
13688c2ecf20Sopenharmony_ci				KNL_EDC_ROUTE, &edc_route_reg[i]);
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci		if (i > 0 && edc_route_reg[i] != edc_route_reg[i-1]) {
13718c2ecf20Sopenharmony_ci			knl_show_edc_route(edc_route_reg[i-1],
13728c2ecf20Sopenharmony_ci					edc_route_string);
13738c2ecf20Sopenharmony_ci			if (cur_reg_start == i-1)
13748c2ecf20Sopenharmony_ci				edac_dbg(0, "edc route table for CHA %d: %s\n",
13758c2ecf20Sopenharmony_ci					cur_reg_start, edc_route_string);
13768c2ecf20Sopenharmony_ci			else
13778c2ecf20Sopenharmony_ci				edac_dbg(0, "edc route table for CHA %d-%d: %s\n",
13788c2ecf20Sopenharmony_ci					cur_reg_start, i-1, edc_route_string);
13798c2ecf20Sopenharmony_ci			cur_reg_start = i;
13808c2ecf20Sopenharmony_ci		}
13818c2ecf20Sopenharmony_ci	}
13828c2ecf20Sopenharmony_ci	knl_show_edc_route(edc_route_reg[i-1], edc_route_string);
13838c2ecf20Sopenharmony_ci	if (cur_reg_start == i-1)
13848c2ecf20Sopenharmony_ci		edac_dbg(0, "edc route table for CHA %d: %s\n",
13858c2ecf20Sopenharmony_ci			cur_reg_start, edc_route_string);
13868c2ecf20Sopenharmony_ci	else
13878c2ecf20Sopenharmony_ci		edac_dbg(0, "edc route table for CHA %d-%d: %s\n",
13888c2ecf20Sopenharmony_ci			cur_reg_start, i-1, edc_route_string);
13898c2ecf20Sopenharmony_ci
13908c2ecf20Sopenharmony_ci	/* Read the MC route table in each CHA. */
13918c2ecf20Sopenharmony_ci	cur_reg_start = 0;
13928c2ecf20Sopenharmony_ci	for (i = 0; i < KNL_MAX_CHAS; i++) {
13938c2ecf20Sopenharmony_ci		pci_read_config_dword(pvt->knl.pci_cha[i],
13948c2ecf20Sopenharmony_ci			KNL_MC_ROUTE, &mc_route_reg[i]);
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci		if (i > 0 && mc_route_reg[i] != mc_route_reg[i-1]) {
13978c2ecf20Sopenharmony_ci			knl_show_mc_route(mc_route_reg[i-1], mc_route_string);
13988c2ecf20Sopenharmony_ci			if (cur_reg_start == i-1)
13998c2ecf20Sopenharmony_ci				edac_dbg(0, "mc route table for CHA %d: %s\n",
14008c2ecf20Sopenharmony_ci					cur_reg_start, mc_route_string);
14018c2ecf20Sopenharmony_ci			else
14028c2ecf20Sopenharmony_ci				edac_dbg(0, "mc route table for CHA %d-%d: %s\n",
14038c2ecf20Sopenharmony_ci					cur_reg_start, i-1, mc_route_string);
14048c2ecf20Sopenharmony_ci			cur_reg_start = i;
14058c2ecf20Sopenharmony_ci		}
14068c2ecf20Sopenharmony_ci	}
14078c2ecf20Sopenharmony_ci	knl_show_mc_route(mc_route_reg[i-1], mc_route_string);
14088c2ecf20Sopenharmony_ci	if (cur_reg_start == i-1)
14098c2ecf20Sopenharmony_ci		edac_dbg(0, "mc route table for CHA %d: %s\n",
14108c2ecf20Sopenharmony_ci			cur_reg_start, mc_route_string);
14118c2ecf20Sopenharmony_ci	else
14128c2ecf20Sopenharmony_ci		edac_dbg(0, "mc route table for CHA %d-%d: %s\n",
14138c2ecf20Sopenharmony_ci			cur_reg_start, i-1, mc_route_string);
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	/* Process DRAM rules */
14168c2ecf20Sopenharmony_ci	for (sad_rule = 0; sad_rule < pvt->info.max_sad; sad_rule++) {
14178c2ecf20Sopenharmony_ci		/* previous limit becomes the new base */
14188c2ecf20Sopenharmony_ci		sad_base = sad_limit;
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci		pci_read_config_dword(pvt->pci_sad0,
14218c2ecf20Sopenharmony_ci			pvt->info.dram_rule[sad_rule], &dram_rule);
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci		if (!DRAM_RULE_ENABLE(dram_rule))
14248c2ecf20Sopenharmony_ci			break;
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci		edram_only = KNL_EDRAM_ONLY(dram_rule);
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci		sad_limit = pvt->info.sad_limit(dram_rule)+1;
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci		pci_read_config_dword(pvt->pci_sad0,
14318c2ecf20Sopenharmony_ci			pvt->info.interleave_list[sad_rule], &interleave_reg);
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_ci		/*
14348c2ecf20Sopenharmony_ci		 * Find out how many ways this dram rule is interleaved.
14358c2ecf20Sopenharmony_ci		 * We stop when we see the first channel again.
14368c2ecf20Sopenharmony_ci		 */
14378c2ecf20Sopenharmony_ci		first_pkg = sad_pkg(pvt->info.interleave_pkg,
14388c2ecf20Sopenharmony_ci						interleave_reg, 0);
14398c2ecf20Sopenharmony_ci		for (intrlv_ways = 1; intrlv_ways < 8; intrlv_ways++) {
14408c2ecf20Sopenharmony_ci			pkg = sad_pkg(pvt->info.interleave_pkg,
14418c2ecf20Sopenharmony_ci						interleave_reg, intrlv_ways);
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci			if ((pkg & 0x8) == 0) {
14448c2ecf20Sopenharmony_ci				/*
14458c2ecf20Sopenharmony_ci				 * 0 bit means memory is non-local,
14468c2ecf20Sopenharmony_ci				 * which KNL doesn't support
14478c2ecf20Sopenharmony_ci				 */
14488c2ecf20Sopenharmony_ci				edac_dbg(0, "Unexpected interleave target %d\n",
14498c2ecf20Sopenharmony_ci					pkg);
14508c2ecf20Sopenharmony_ci				return -1;
14518c2ecf20Sopenharmony_ci			}
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci			if (pkg == first_pkg)
14548c2ecf20Sopenharmony_ci				break;
14558c2ecf20Sopenharmony_ci		}
14568c2ecf20Sopenharmony_ci		if (KNL_MOD3(dram_rule))
14578c2ecf20Sopenharmony_ci			intrlv_ways *= 3;
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci		edac_dbg(3, "dram rule %d (base 0x%llx, limit 0x%llx), %d way interleave%s\n",
14608c2ecf20Sopenharmony_ci			sad_rule,
14618c2ecf20Sopenharmony_ci			sad_base,
14628c2ecf20Sopenharmony_ci			sad_limit,
14638c2ecf20Sopenharmony_ci			intrlv_ways,
14648c2ecf20Sopenharmony_ci			edram_only ? ", EDRAM" : "");
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_ci		/*
14678c2ecf20Sopenharmony_ci		 * Find out how big the SAD region really is by iterating
14688c2ecf20Sopenharmony_ci		 * over TAD tables (SAD regions may contain holes).
14698c2ecf20Sopenharmony_ci		 * Each memory controller might have a different TAD table, so
14708c2ecf20Sopenharmony_ci		 * we have to look at both.
14718c2ecf20Sopenharmony_ci		 *
14728c2ecf20Sopenharmony_ci		 * Livespace is the memory that's mapped in this TAD table,
14738c2ecf20Sopenharmony_ci		 * deadspace is the holes (this could be the MMIO hole, or it
14748c2ecf20Sopenharmony_ci		 * could be memory that's mapped by the other TAD table but
14758c2ecf20Sopenharmony_ci		 * not this one).
14768c2ecf20Sopenharmony_ci		 */
14778c2ecf20Sopenharmony_ci		for (mc = 0; mc < 2; mc++) {
14788c2ecf20Sopenharmony_ci			sad_actual_size[mc] = 0;
14798c2ecf20Sopenharmony_ci			tad_livespace = 0;
14808c2ecf20Sopenharmony_ci			for (tad_rule = 0;
14818c2ecf20Sopenharmony_ci					tad_rule < ARRAY_SIZE(
14828c2ecf20Sopenharmony_ci						knl_tad_dram_limit_lo);
14838c2ecf20Sopenharmony_ci					tad_rule++) {
14848c2ecf20Sopenharmony_ci				if (knl_get_tad(pvt,
14858c2ecf20Sopenharmony_ci						tad_rule,
14868c2ecf20Sopenharmony_ci						mc,
14878c2ecf20Sopenharmony_ci						&tad_deadspace,
14888c2ecf20Sopenharmony_ci						&tad_limit,
14898c2ecf20Sopenharmony_ci						&tad_ways))
14908c2ecf20Sopenharmony_ci					break;
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci				tad_size = (tad_limit+1) -
14938c2ecf20Sopenharmony_ci					(tad_livespace + tad_deadspace);
14948c2ecf20Sopenharmony_ci				tad_livespace += tad_size;
14958c2ecf20Sopenharmony_ci				tad_base = (tad_limit+1) - tad_size;
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci				if (tad_base < sad_base) {
14988c2ecf20Sopenharmony_ci					if (tad_limit > sad_base)
14998c2ecf20Sopenharmony_ci						edac_dbg(0, "TAD region overlaps lower SAD boundary -- TAD tables may be configured incorrectly.\n");
15008c2ecf20Sopenharmony_ci				} else if (tad_base < sad_limit) {
15018c2ecf20Sopenharmony_ci					if (tad_limit+1 > sad_limit) {
15028c2ecf20Sopenharmony_ci						edac_dbg(0, "TAD region overlaps upper SAD boundary -- TAD tables may be configured incorrectly.\n");
15038c2ecf20Sopenharmony_ci					} else {
15048c2ecf20Sopenharmony_ci						/* TAD region is completely inside SAD region */
15058c2ecf20Sopenharmony_ci						edac_dbg(3, "TAD region %d 0x%llx - 0x%llx (%lld bytes) table%d\n",
15068c2ecf20Sopenharmony_ci							tad_rule, tad_base,
15078c2ecf20Sopenharmony_ci							tad_limit, tad_size,
15088c2ecf20Sopenharmony_ci							mc);
15098c2ecf20Sopenharmony_ci						sad_actual_size[mc] += tad_size;
15108c2ecf20Sopenharmony_ci					}
15118c2ecf20Sopenharmony_ci				}
15128c2ecf20Sopenharmony_ci			}
15138c2ecf20Sopenharmony_ci		}
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci		for (mc = 0; mc < 2; mc++) {
15168c2ecf20Sopenharmony_ci			edac_dbg(3, " total TAD DRAM footprint in table%d : 0x%llx (%lld bytes)\n",
15178c2ecf20Sopenharmony_ci				mc, sad_actual_size[mc], sad_actual_size[mc]);
15188c2ecf20Sopenharmony_ci		}
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci		/* Ignore EDRAM rule */
15218c2ecf20Sopenharmony_ci		if (edram_only)
15228c2ecf20Sopenharmony_ci			continue;
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_ci		/* Figure out which channels participate in interleave. */
15258c2ecf20Sopenharmony_ci		for (channel = 0; channel < KNL_MAX_CHANNELS; channel++)
15268c2ecf20Sopenharmony_ci			participants[channel] = 0;
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci		/* For each channel, does at least one CHA have
15298c2ecf20Sopenharmony_ci		 * this channel mapped to the given target?
15308c2ecf20Sopenharmony_ci		 */
15318c2ecf20Sopenharmony_ci		for (channel = 0; channel < KNL_MAX_CHANNELS; channel++) {
15328c2ecf20Sopenharmony_ci			int target;
15338c2ecf20Sopenharmony_ci			int cha;
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci			for (target = 0; target < KNL_MAX_CHANNELS; target++) {
15368c2ecf20Sopenharmony_ci				for (cha = 0; cha < KNL_MAX_CHAS; cha++) {
15378c2ecf20Sopenharmony_ci					if (knl_get_mc_route(target,
15388c2ecf20Sopenharmony_ci						mc_route_reg[cha]) == channel
15398c2ecf20Sopenharmony_ci						&& !participants[channel]) {
15408c2ecf20Sopenharmony_ci						participants[channel] = 1;
15418c2ecf20Sopenharmony_ci						break;
15428c2ecf20Sopenharmony_ci					}
15438c2ecf20Sopenharmony_ci				}
15448c2ecf20Sopenharmony_ci			}
15458c2ecf20Sopenharmony_ci		}
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_ci		for (channel = 0; channel < KNL_MAX_CHANNELS; channel++) {
15488c2ecf20Sopenharmony_ci			mc = knl_channel_mc(channel);
15498c2ecf20Sopenharmony_ci			if (participants[channel]) {
15508c2ecf20Sopenharmony_ci				edac_dbg(4, "mc channel %d contributes %lld bytes via sad entry %d\n",
15518c2ecf20Sopenharmony_ci					channel,
15528c2ecf20Sopenharmony_ci					sad_actual_size[mc]/intrlv_ways,
15538c2ecf20Sopenharmony_ci					sad_rule);
15548c2ecf20Sopenharmony_ci				mc_sizes[channel] +=
15558c2ecf20Sopenharmony_ci					sad_actual_size[mc]/intrlv_ways;
15568c2ecf20Sopenharmony_ci			}
15578c2ecf20Sopenharmony_ci		}
15588c2ecf20Sopenharmony_ci	}
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	return 0;
15618c2ecf20Sopenharmony_ci}
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_cistatic void get_source_id(struct mem_ctl_info *mci)
15648c2ecf20Sopenharmony_ci{
15658c2ecf20Sopenharmony_ci	struct sbridge_pvt *pvt = mci->pvt_info;
15668c2ecf20Sopenharmony_ci	u32 reg;
15678c2ecf20Sopenharmony_ci
15688c2ecf20Sopenharmony_ci	if (pvt->info.type == HASWELL || pvt->info.type == BROADWELL ||
15698c2ecf20Sopenharmony_ci	    pvt->info.type == KNIGHTS_LANDING)
15708c2ecf20Sopenharmony_ci		pci_read_config_dword(pvt->pci_sad1, SAD_TARGET, &reg);
15718c2ecf20Sopenharmony_ci	else
15728c2ecf20Sopenharmony_ci		pci_read_config_dword(pvt->pci_br0, SAD_TARGET, &reg);
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci	if (pvt->info.type == KNIGHTS_LANDING)
15758c2ecf20Sopenharmony_ci		pvt->sbridge_dev->source_id = SOURCE_ID_KNL(reg);
15768c2ecf20Sopenharmony_ci	else
15778c2ecf20Sopenharmony_ci		pvt->sbridge_dev->source_id = SOURCE_ID(reg);
15788c2ecf20Sopenharmony_ci}
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_cistatic int __populate_dimms(struct mem_ctl_info *mci,
15818c2ecf20Sopenharmony_ci			    u64 knl_mc_sizes[KNL_MAX_CHANNELS],
15828c2ecf20Sopenharmony_ci			    enum edac_type mode)
15838c2ecf20Sopenharmony_ci{
15848c2ecf20Sopenharmony_ci	struct sbridge_pvt *pvt = mci->pvt_info;
15858c2ecf20Sopenharmony_ci	int channels = pvt->info.type == KNIGHTS_LANDING ? KNL_MAX_CHANNELS
15868c2ecf20Sopenharmony_ci							 : NUM_CHANNELS;
15878c2ecf20Sopenharmony_ci	unsigned int i, j, banks, ranks, rows, cols, npages;
15888c2ecf20Sopenharmony_ci	struct dimm_info *dimm;
15898c2ecf20Sopenharmony_ci	enum mem_type mtype;
15908c2ecf20Sopenharmony_ci	u64 size;
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_ci	mtype = pvt->info.get_memory_type(pvt);
15938c2ecf20Sopenharmony_ci	if (mtype == MEM_RDDR3 || mtype == MEM_RDDR4)
15948c2ecf20Sopenharmony_ci		edac_dbg(0, "Memory is registered\n");
15958c2ecf20Sopenharmony_ci	else if (mtype == MEM_UNKNOWN)
15968c2ecf20Sopenharmony_ci		edac_dbg(0, "Cannot determine memory type\n");
15978c2ecf20Sopenharmony_ci	else
15988c2ecf20Sopenharmony_ci		edac_dbg(0, "Memory is unregistered\n");
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_ci	if (mtype == MEM_DDR4 || mtype == MEM_RDDR4)
16018c2ecf20Sopenharmony_ci		banks = 16;
16028c2ecf20Sopenharmony_ci	else
16038c2ecf20Sopenharmony_ci		banks = 8;
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci	for (i = 0; i < channels; i++) {
16068c2ecf20Sopenharmony_ci		u32 mtr;
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci		int max_dimms_per_channel;
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci		if (pvt->info.type == KNIGHTS_LANDING) {
16118c2ecf20Sopenharmony_ci			max_dimms_per_channel = 1;
16128c2ecf20Sopenharmony_ci			if (!pvt->knl.pci_channel[i])
16138c2ecf20Sopenharmony_ci				continue;
16148c2ecf20Sopenharmony_ci		} else {
16158c2ecf20Sopenharmony_ci			max_dimms_per_channel = ARRAY_SIZE(mtr_regs);
16168c2ecf20Sopenharmony_ci			if (!pvt->pci_tad[i])
16178c2ecf20Sopenharmony_ci				continue;
16188c2ecf20Sopenharmony_ci		}
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci		for (j = 0; j < max_dimms_per_channel; j++) {
16218c2ecf20Sopenharmony_ci			dimm = edac_get_dimm(mci, i, j, 0);
16228c2ecf20Sopenharmony_ci			if (pvt->info.type == KNIGHTS_LANDING) {
16238c2ecf20Sopenharmony_ci				pci_read_config_dword(pvt->knl.pci_channel[i],
16248c2ecf20Sopenharmony_ci					knl_mtr_reg, &mtr);
16258c2ecf20Sopenharmony_ci			} else {
16268c2ecf20Sopenharmony_ci				pci_read_config_dword(pvt->pci_tad[i],
16278c2ecf20Sopenharmony_ci					mtr_regs[j], &mtr);
16288c2ecf20Sopenharmony_ci			}
16298c2ecf20Sopenharmony_ci			edac_dbg(4, "Channel #%d  MTR%d = %x\n", i, j, mtr);
16308c2ecf20Sopenharmony_ci			if (IS_DIMM_PRESENT(mtr)) {
16318c2ecf20Sopenharmony_ci				if (!IS_ECC_ENABLED(pvt->info.mcmtr)) {
16328c2ecf20Sopenharmony_ci					sbridge_printk(KERN_ERR, "CPU SrcID #%d, Ha #%d, Channel #%d has DIMMs, but ECC is disabled\n",
16338c2ecf20Sopenharmony_ci						       pvt->sbridge_dev->source_id,
16348c2ecf20Sopenharmony_ci						       pvt->sbridge_dev->dom, i);
16358c2ecf20Sopenharmony_ci					return -ENODEV;
16368c2ecf20Sopenharmony_ci				}
16378c2ecf20Sopenharmony_ci				pvt->channel[i].dimms++;
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci				ranks = numrank(pvt->info.type, mtr);
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci				if (pvt->info.type == KNIGHTS_LANDING) {
16428c2ecf20Sopenharmony_ci					/* For DDR4, this is fixed. */
16438c2ecf20Sopenharmony_ci					cols = 1 << 10;
16448c2ecf20Sopenharmony_ci					rows = knl_mc_sizes[i] /
16458c2ecf20Sopenharmony_ci						((u64) cols * ranks * banks * 8);
16468c2ecf20Sopenharmony_ci				} else {
16478c2ecf20Sopenharmony_ci					rows = numrow(mtr);
16488c2ecf20Sopenharmony_ci					cols = numcol(mtr);
16498c2ecf20Sopenharmony_ci				}
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci				size = ((u64)rows * cols * banks * ranks) >> (20 - 3);
16528c2ecf20Sopenharmony_ci				npages = MiB_TO_PAGES(size);
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci				edac_dbg(0, "mc#%d: ha %d channel %d, dimm %d, %lld MiB (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n",
16558c2ecf20Sopenharmony_ci					 pvt->sbridge_dev->mc, pvt->sbridge_dev->dom, i, j,
16568c2ecf20Sopenharmony_ci					 size, npages,
16578c2ecf20Sopenharmony_ci					 banks, ranks, rows, cols);
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci				dimm->nr_pages = npages;
16608c2ecf20Sopenharmony_ci				dimm->grain = 32;
16618c2ecf20Sopenharmony_ci				dimm->dtype = pvt->info.get_width(pvt, mtr);
16628c2ecf20Sopenharmony_ci				dimm->mtype = mtype;
16638c2ecf20Sopenharmony_ci				dimm->edac_mode = mode;
16648c2ecf20Sopenharmony_ci				snprintf(dimm->label, sizeof(dimm->label),
16658c2ecf20Sopenharmony_ci						 "CPU_SrcID#%u_Ha#%u_Chan#%u_DIMM#%u",
16668c2ecf20Sopenharmony_ci						 pvt->sbridge_dev->source_id, pvt->sbridge_dev->dom, i, j);
16678c2ecf20Sopenharmony_ci			}
16688c2ecf20Sopenharmony_ci		}
16698c2ecf20Sopenharmony_ci	}
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci	return 0;
16728c2ecf20Sopenharmony_ci}
16738c2ecf20Sopenharmony_ci
16748c2ecf20Sopenharmony_cistatic int get_dimm_config(struct mem_ctl_info *mci)
16758c2ecf20Sopenharmony_ci{
16768c2ecf20Sopenharmony_ci	struct sbridge_pvt *pvt = mci->pvt_info;
16778c2ecf20Sopenharmony_ci	u64 knl_mc_sizes[KNL_MAX_CHANNELS];
16788c2ecf20Sopenharmony_ci	enum edac_type mode;
16798c2ecf20Sopenharmony_ci	u32 reg;
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci	pvt->sbridge_dev->node_id = pvt->info.get_node_id(pvt);
16828c2ecf20Sopenharmony_ci	edac_dbg(0, "mc#%d: Node ID: %d, source ID: %d\n",
16838c2ecf20Sopenharmony_ci		 pvt->sbridge_dev->mc,
16848c2ecf20Sopenharmony_ci		 pvt->sbridge_dev->node_id,
16858c2ecf20Sopenharmony_ci		 pvt->sbridge_dev->source_id);
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci	/* KNL doesn't support mirroring or lockstep,
16888c2ecf20Sopenharmony_ci	 * and is always closed page
16898c2ecf20Sopenharmony_ci	 */
16908c2ecf20Sopenharmony_ci	if (pvt->info.type == KNIGHTS_LANDING) {
16918c2ecf20Sopenharmony_ci		mode = EDAC_S4ECD4ED;
16928c2ecf20Sopenharmony_ci		pvt->mirror_mode = NON_MIRRORING;
16938c2ecf20Sopenharmony_ci		pvt->is_cur_addr_mirrored = false;
16948c2ecf20Sopenharmony_ci
16958c2ecf20Sopenharmony_ci		if (knl_get_dimm_capacity(pvt, knl_mc_sizes) != 0)
16968c2ecf20Sopenharmony_ci			return -1;
16978c2ecf20Sopenharmony_ci		if (pci_read_config_dword(pvt->pci_ta, KNL_MCMTR, &pvt->info.mcmtr)) {
16988c2ecf20Sopenharmony_ci			edac_dbg(0, "Failed to read KNL_MCMTR register\n");
16998c2ecf20Sopenharmony_ci			return -ENODEV;
17008c2ecf20Sopenharmony_ci		}
17018c2ecf20Sopenharmony_ci	} else {
17028c2ecf20Sopenharmony_ci		if (pvt->info.type == HASWELL || pvt->info.type == BROADWELL) {
17038c2ecf20Sopenharmony_ci			if (pci_read_config_dword(pvt->pci_ha, HASWELL_HASYSDEFEATURE2, &reg)) {
17048c2ecf20Sopenharmony_ci				edac_dbg(0, "Failed to read HASWELL_HASYSDEFEATURE2 register\n");
17058c2ecf20Sopenharmony_ci				return -ENODEV;
17068c2ecf20Sopenharmony_ci			}
17078c2ecf20Sopenharmony_ci			pvt->is_chan_hash = GET_BITFIELD(reg, 21, 21);
17088c2ecf20Sopenharmony_ci			if (GET_BITFIELD(reg, 28, 28)) {
17098c2ecf20Sopenharmony_ci				pvt->mirror_mode = ADDR_RANGE_MIRRORING;
17108c2ecf20Sopenharmony_ci				edac_dbg(0, "Address range partial memory mirroring is enabled\n");
17118c2ecf20Sopenharmony_ci				goto next;
17128c2ecf20Sopenharmony_ci			}
17138c2ecf20Sopenharmony_ci		}
17148c2ecf20Sopenharmony_ci		if (pci_read_config_dword(pvt->pci_ras, RASENABLES, &reg)) {
17158c2ecf20Sopenharmony_ci			edac_dbg(0, "Failed to read RASENABLES register\n");
17168c2ecf20Sopenharmony_ci			return -ENODEV;
17178c2ecf20Sopenharmony_ci		}
17188c2ecf20Sopenharmony_ci		if (IS_MIRROR_ENABLED(reg)) {
17198c2ecf20Sopenharmony_ci			pvt->mirror_mode = FULL_MIRRORING;
17208c2ecf20Sopenharmony_ci			edac_dbg(0, "Full memory mirroring is enabled\n");
17218c2ecf20Sopenharmony_ci		} else {
17228c2ecf20Sopenharmony_ci			pvt->mirror_mode = NON_MIRRORING;
17238c2ecf20Sopenharmony_ci			edac_dbg(0, "Memory mirroring is disabled\n");
17248c2ecf20Sopenharmony_ci		}
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_cinext:
17278c2ecf20Sopenharmony_ci		if (pci_read_config_dword(pvt->pci_ta, MCMTR, &pvt->info.mcmtr)) {
17288c2ecf20Sopenharmony_ci			edac_dbg(0, "Failed to read MCMTR register\n");
17298c2ecf20Sopenharmony_ci			return -ENODEV;
17308c2ecf20Sopenharmony_ci		}
17318c2ecf20Sopenharmony_ci		if (IS_LOCKSTEP_ENABLED(pvt->info.mcmtr)) {
17328c2ecf20Sopenharmony_ci			edac_dbg(0, "Lockstep is enabled\n");
17338c2ecf20Sopenharmony_ci			mode = EDAC_S8ECD8ED;
17348c2ecf20Sopenharmony_ci			pvt->is_lockstep = true;
17358c2ecf20Sopenharmony_ci		} else {
17368c2ecf20Sopenharmony_ci			edac_dbg(0, "Lockstep is disabled\n");
17378c2ecf20Sopenharmony_ci			mode = EDAC_S4ECD4ED;
17388c2ecf20Sopenharmony_ci			pvt->is_lockstep = false;
17398c2ecf20Sopenharmony_ci		}
17408c2ecf20Sopenharmony_ci		if (IS_CLOSE_PG(pvt->info.mcmtr)) {
17418c2ecf20Sopenharmony_ci			edac_dbg(0, "address map is on closed page mode\n");
17428c2ecf20Sopenharmony_ci			pvt->is_close_pg = true;
17438c2ecf20Sopenharmony_ci		} else {
17448c2ecf20Sopenharmony_ci			edac_dbg(0, "address map is on open page mode\n");
17458c2ecf20Sopenharmony_ci			pvt->is_close_pg = false;
17468c2ecf20Sopenharmony_ci		}
17478c2ecf20Sopenharmony_ci	}
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_ci	return __populate_dimms(mci, knl_mc_sizes, mode);
17508c2ecf20Sopenharmony_ci}
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_cistatic void get_memory_layout(const struct mem_ctl_info *mci)
17538c2ecf20Sopenharmony_ci{
17548c2ecf20Sopenharmony_ci	struct sbridge_pvt *pvt = mci->pvt_info;
17558c2ecf20Sopenharmony_ci	int i, j, k, n_sads, n_tads, sad_interl;
17568c2ecf20Sopenharmony_ci	u32 reg;
17578c2ecf20Sopenharmony_ci	u64 limit, prv = 0;
17588c2ecf20Sopenharmony_ci	u64 tmp_mb;
17598c2ecf20Sopenharmony_ci	u32 gb, mb;
17608c2ecf20Sopenharmony_ci	u32 rir_way;
17618c2ecf20Sopenharmony_ci
17628c2ecf20Sopenharmony_ci	/*
17638c2ecf20Sopenharmony_ci	 * Step 1) Get TOLM/TOHM ranges
17648c2ecf20Sopenharmony_ci	 */
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci	pvt->tolm = pvt->info.get_tolm(pvt);
17678c2ecf20Sopenharmony_ci	tmp_mb = (1 + pvt->tolm) >> 20;
17688c2ecf20Sopenharmony_ci
17698c2ecf20Sopenharmony_ci	gb = div_u64_rem(tmp_mb, 1024, &mb);
17708c2ecf20Sopenharmony_ci	edac_dbg(0, "TOLM: %u.%03u GB (0x%016Lx)\n",
17718c2ecf20Sopenharmony_ci		gb, (mb*1000)/1024, (u64)pvt->tolm);
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci	/* Address range is already 45:25 */
17748c2ecf20Sopenharmony_ci	pvt->tohm = pvt->info.get_tohm(pvt);
17758c2ecf20Sopenharmony_ci	tmp_mb = (1 + pvt->tohm) >> 20;
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_ci	gb = div_u64_rem(tmp_mb, 1024, &mb);
17788c2ecf20Sopenharmony_ci	edac_dbg(0, "TOHM: %u.%03u GB (0x%016Lx)\n",
17798c2ecf20Sopenharmony_ci		gb, (mb*1000)/1024, (u64)pvt->tohm);
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci	/*
17828c2ecf20Sopenharmony_ci	 * Step 2) Get SAD range and SAD Interleave list
17838c2ecf20Sopenharmony_ci	 * TAD registers contain the interleave wayness. However, it
17848c2ecf20Sopenharmony_ci	 * seems simpler to just discover it indirectly, with the
17858c2ecf20Sopenharmony_ci	 * algorithm bellow.
17868c2ecf20Sopenharmony_ci	 */
17878c2ecf20Sopenharmony_ci	prv = 0;
17888c2ecf20Sopenharmony_ci	for (n_sads = 0; n_sads < pvt->info.max_sad; n_sads++) {
17898c2ecf20Sopenharmony_ci		/* SAD_LIMIT Address range is 45:26 */
17908c2ecf20Sopenharmony_ci		pci_read_config_dword(pvt->pci_sad0, pvt->info.dram_rule[n_sads],
17918c2ecf20Sopenharmony_ci				      &reg);
17928c2ecf20Sopenharmony_ci		limit = pvt->info.sad_limit(reg);
17938c2ecf20Sopenharmony_ci
17948c2ecf20Sopenharmony_ci		if (!DRAM_RULE_ENABLE(reg))
17958c2ecf20Sopenharmony_ci			continue;
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci		if (limit <= prv)
17988c2ecf20Sopenharmony_ci			break;
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_ci		tmp_mb = (limit + 1) >> 20;
18018c2ecf20Sopenharmony_ci		gb = div_u64_rem(tmp_mb, 1024, &mb);
18028c2ecf20Sopenharmony_ci		edac_dbg(0, "SAD#%d %s up to %u.%03u GB (0x%016Lx) Interleave: %s reg=0x%08x\n",
18038c2ecf20Sopenharmony_ci			 n_sads,
18048c2ecf20Sopenharmony_ci			 show_dram_attr(pvt->info.dram_attr(reg)),
18058c2ecf20Sopenharmony_ci			 gb, (mb*1000)/1024,
18068c2ecf20Sopenharmony_ci			 ((u64)tmp_mb) << 20L,
18078c2ecf20Sopenharmony_ci			 get_intlv_mode_str(reg, pvt->info.type),
18088c2ecf20Sopenharmony_ci			 reg);
18098c2ecf20Sopenharmony_ci		prv = limit;
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_ci		pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads],
18128c2ecf20Sopenharmony_ci				      &reg);
18138c2ecf20Sopenharmony_ci		sad_interl = sad_pkg(pvt->info.interleave_pkg, reg, 0);
18148c2ecf20Sopenharmony_ci		for (j = 0; j < 8; j++) {
18158c2ecf20Sopenharmony_ci			u32 pkg = sad_pkg(pvt->info.interleave_pkg, reg, j);
18168c2ecf20Sopenharmony_ci			if (j > 0 && sad_interl == pkg)
18178c2ecf20Sopenharmony_ci				break;
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci			edac_dbg(0, "SAD#%d, interleave #%d: %d\n",
18208c2ecf20Sopenharmony_ci				 n_sads, j, pkg);
18218c2ecf20Sopenharmony_ci		}
18228c2ecf20Sopenharmony_ci	}
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_ci	if (pvt->info.type == KNIGHTS_LANDING)
18258c2ecf20Sopenharmony_ci		return;
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_ci	/*
18288c2ecf20Sopenharmony_ci	 * Step 3) Get TAD range
18298c2ecf20Sopenharmony_ci	 */
18308c2ecf20Sopenharmony_ci	prv = 0;
18318c2ecf20Sopenharmony_ci	for (n_tads = 0; n_tads < MAX_TAD; n_tads++) {
18328c2ecf20Sopenharmony_ci		pci_read_config_dword(pvt->pci_ha, tad_dram_rule[n_tads], &reg);
18338c2ecf20Sopenharmony_ci		limit = TAD_LIMIT(reg);
18348c2ecf20Sopenharmony_ci		if (limit <= prv)
18358c2ecf20Sopenharmony_ci			break;
18368c2ecf20Sopenharmony_ci		tmp_mb = (limit + 1) >> 20;
18378c2ecf20Sopenharmony_ci
18388c2ecf20Sopenharmony_ci		gb = div_u64_rem(tmp_mb, 1024, &mb);
18398c2ecf20Sopenharmony_ci		edac_dbg(0, "TAD#%d: up to %u.%03u GB (0x%016Lx), socket interleave %d, memory interleave %d, TGT: %d, %d, %d, %d, reg=0x%08x\n",
18408c2ecf20Sopenharmony_ci			 n_tads, gb, (mb*1000)/1024,
18418c2ecf20Sopenharmony_ci			 ((u64)tmp_mb) << 20L,
18428c2ecf20Sopenharmony_ci			 (u32)(1 << TAD_SOCK(reg)),
18438c2ecf20Sopenharmony_ci			 (u32)TAD_CH(reg) + 1,
18448c2ecf20Sopenharmony_ci			 (u32)TAD_TGT0(reg),
18458c2ecf20Sopenharmony_ci			 (u32)TAD_TGT1(reg),
18468c2ecf20Sopenharmony_ci			 (u32)TAD_TGT2(reg),
18478c2ecf20Sopenharmony_ci			 (u32)TAD_TGT3(reg),
18488c2ecf20Sopenharmony_ci			 reg);
18498c2ecf20Sopenharmony_ci		prv = limit;
18508c2ecf20Sopenharmony_ci	}
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_ci	/*
18538c2ecf20Sopenharmony_ci	 * Step 4) Get TAD offsets, per each channel
18548c2ecf20Sopenharmony_ci	 */
18558c2ecf20Sopenharmony_ci	for (i = 0; i < NUM_CHANNELS; i++) {
18568c2ecf20Sopenharmony_ci		if (!pvt->channel[i].dimms)
18578c2ecf20Sopenharmony_ci			continue;
18588c2ecf20Sopenharmony_ci		for (j = 0; j < n_tads; j++) {
18598c2ecf20Sopenharmony_ci			pci_read_config_dword(pvt->pci_tad[i],
18608c2ecf20Sopenharmony_ci					      tad_ch_nilv_offset[j],
18618c2ecf20Sopenharmony_ci					      &reg);
18628c2ecf20Sopenharmony_ci			tmp_mb = TAD_OFFSET(reg) >> 20;
18638c2ecf20Sopenharmony_ci			gb = div_u64_rem(tmp_mb, 1024, &mb);
18648c2ecf20Sopenharmony_ci			edac_dbg(0, "TAD CH#%d, offset #%d: %u.%03u GB (0x%016Lx), reg=0x%08x\n",
18658c2ecf20Sopenharmony_ci				 i, j,
18668c2ecf20Sopenharmony_ci				 gb, (mb*1000)/1024,
18678c2ecf20Sopenharmony_ci				 ((u64)tmp_mb) << 20L,
18688c2ecf20Sopenharmony_ci				 reg);
18698c2ecf20Sopenharmony_ci		}
18708c2ecf20Sopenharmony_ci	}
18718c2ecf20Sopenharmony_ci
18728c2ecf20Sopenharmony_ci	/*
18738c2ecf20Sopenharmony_ci	 * Step 6) Get RIR Wayness/Limit, per each channel
18748c2ecf20Sopenharmony_ci	 */
18758c2ecf20Sopenharmony_ci	for (i = 0; i < NUM_CHANNELS; i++) {
18768c2ecf20Sopenharmony_ci		if (!pvt->channel[i].dimms)
18778c2ecf20Sopenharmony_ci			continue;
18788c2ecf20Sopenharmony_ci		for (j = 0; j < MAX_RIR_RANGES; j++) {
18798c2ecf20Sopenharmony_ci			pci_read_config_dword(pvt->pci_tad[i],
18808c2ecf20Sopenharmony_ci					      rir_way_limit[j],
18818c2ecf20Sopenharmony_ci					      &reg);
18828c2ecf20Sopenharmony_ci
18838c2ecf20Sopenharmony_ci			if (!IS_RIR_VALID(reg))
18848c2ecf20Sopenharmony_ci				continue;
18858c2ecf20Sopenharmony_ci
18868c2ecf20Sopenharmony_ci			tmp_mb = pvt->info.rir_limit(reg) >> 20;
18878c2ecf20Sopenharmony_ci			rir_way = 1 << RIR_WAY(reg);
18888c2ecf20Sopenharmony_ci			gb = div_u64_rem(tmp_mb, 1024, &mb);
18898c2ecf20Sopenharmony_ci			edac_dbg(0, "CH#%d RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d, reg=0x%08x\n",
18908c2ecf20Sopenharmony_ci				 i, j,
18918c2ecf20Sopenharmony_ci				 gb, (mb*1000)/1024,
18928c2ecf20Sopenharmony_ci				 ((u64)tmp_mb) << 20L,
18938c2ecf20Sopenharmony_ci				 rir_way,
18948c2ecf20Sopenharmony_ci				 reg);
18958c2ecf20Sopenharmony_ci
18968c2ecf20Sopenharmony_ci			for (k = 0; k < rir_way; k++) {
18978c2ecf20Sopenharmony_ci				pci_read_config_dword(pvt->pci_tad[i],
18988c2ecf20Sopenharmony_ci						      rir_offset[j][k],
18998c2ecf20Sopenharmony_ci						      &reg);
19008c2ecf20Sopenharmony_ci				tmp_mb = RIR_OFFSET(pvt->info.type, reg) << 6;
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci				gb = div_u64_rem(tmp_mb, 1024, &mb);
19038c2ecf20Sopenharmony_ci				edac_dbg(0, "CH#%d RIR#%d INTL#%d, offset %u.%03u GB (0x%016Lx), tgt: %d, reg=0x%08x\n",
19048c2ecf20Sopenharmony_ci					 i, j, k,
19058c2ecf20Sopenharmony_ci					 gb, (mb*1000)/1024,
19068c2ecf20Sopenharmony_ci					 ((u64)tmp_mb) << 20L,
19078c2ecf20Sopenharmony_ci					 (u32)RIR_RNK_TGT(pvt->info.type, reg),
19088c2ecf20Sopenharmony_ci					 reg);
19098c2ecf20Sopenharmony_ci			}
19108c2ecf20Sopenharmony_ci		}
19118c2ecf20Sopenharmony_ci	}
19128c2ecf20Sopenharmony_ci}
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_cistatic struct mem_ctl_info *get_mci_for_node_id(u8 node_id, u8 ha)
19158c2ecf20Sopenharmony_ci{
19168c2ecf20Sopenharmony_ci	struct sbridge_dev *sbridge_dev;
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_ci	list_for_each_entry(sbridge_dev, &sbridge_edac_list, list) {
19198c2ecf20Sopenharmony_ci		if (sbridge_dev->node_id == node_id && sbridge_dev->dom == ha)
19208c2ecf20Sopenharmony_ci			return sbridge_dev->mci;
19218c2ecf20Sopenharmony_ci	}
19228c2ecf20Sopenharmony_ci	return NULL;
19238c2ecf20Sopenharmony_ci}
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_cistatic int get_memory_error_data(struct mem_ctl_info *mci,
19268c2ecf20Sopenharmony_ci				 u64 addr,
19278c2ecf20Sopenharmony_ci				 u8 *socket, u8 *ha,
19288c2ecf20Sopenharmony_ci				 long *channel_mask,
19298c2ecf20Sopenharmony_ci				 u8 *rank,
19308c2ecf20Sopenharmony_ci				 char **area_type, char *msg)
19318c2ecf20Sopenharmony_ci{
19328c2ecf20Sopenharmony_ci	struct mem_ctl_info	*new_mci;
19338c2ecf20Sopenharmony_ci	struct sbridge_pvt *pvt = mci->pvt_info;
19348c2ecf20Sopenharmony_ci	struct pci_dev		*pci_ha;
19358c2ecf20Sopenharmony_ci	int			n_rir, n_sads, n_tads, sad_way, sck_xch;
19368c2ecf20Sopenharmony_ci	int			sad_interl, idx, base_ch;
19378c2ecf20Sopenharmony_ci	int			interleave_mode, shiftup = 0;
19388c2ecf20Sopenharmony_ci	unsigned int		sad_interleave[MAX_INTERLEAVE];
19398c2ecf20Sopenharmony_ci	u32			reg, dram_rule;
19408c2ecf20Sopenharmony_ci	u8			ch_way, sck_way, pkg, sad_ha = 0;
19418c2ecf20Sopenharmony_ci	u32			tad_offset;
19428c2ecf20Sopenharmony_ci	u32			rir_way;
19438c2ecf20Sopenharmony_ci	u32			mb, gb;
19448c2ecf20Sopenharmony_ci	u64			ch_addr, offset, limit = 0, prv = 0;
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_ci
19478c2ecf20Sopenharmony_ci	/*
19488c2ecf20Sopenharmony_ci	 * Step 0) Check if the address is at special memory ranges
19498c2ecf20Sopenharmony_ci	 * The check bellow is probably enough to fill all cases where
19508c2ecf20Sopenharmony_ci	 * the error is not inside a memory, except for the legacy
19518c2ecf20Sopenharmony_ci	 * range (e. g. VGA addresses). It is unlikely, however, that the
19528c2ecf20Sopenharmony_ci	 * memory controller would generate an error on that range.
19538c2ecf20Sopenharmony_ci	 */
19548c2ecf20Sopenharmony_ci	if ((addr > (u64) pvt->tolm) && (addr < (1LL << 32))) {
19558c2ecf20Sopenharmony_ci		sprintf(msg, "Error at TOLM area, on addr 0x%08Lx", addr);
19568c2ecf20Sopenharmony_ci		return -EINVAL;
19578c2ecf20Sopenharmony_ci	}
19588c2ecf20Sopenharmony_ci	if (addr >= (u64)pvt->tohm) {
19598c2ecf20Sopenharmony_ci		sprintf(msg, "Error at MMIOH area, on addr 0x%016Lx", addr);
19608c2ecf20Sopenharmony_ci		return -EINVAL;
19618c2ecf20Sopenharmony_ci	}
19628c2ecf20Sopenharmony_ci
19638c2ecf20Sopenharmony_ci	/*
19648c2ecf20Sopenharmony_ci	 * Step 1) Get socket
19658c2ecf20Sopenharmony_ci	 */
19668c2ecf20Sopenharmony_ci	for (n_sads = 0; n_sads < pvt->info.max_sad; n_sads++) {
19678c2ecf20Sopenharmony_ci		pci_read_config_dword(pvt->pci_sad0, pvt->info.dram_rule[n_sads],
19688c2ecf20Sopenharmony_ci				      &reg);
19698c2ecf20Sopenharmony_ci
19708c2ecf20Sopenharmony_ci		if (!DRAM_RULE_ENABLE(reg))
19718c2ecf20Sopenharmony_ci			continue;
19728c2ecf20Sopenharmony_ci
19738c2ecf20Sopenharmony_ci		limit = pvt->info.sad_limit(reg);
19748c2ecf20Sopenharmony_ci		if (limit <= prv) {
19758c2ecf20Sopenharmony_ci			sprintf(msg, "Can't discover the memory socket");
19768c2ecf20Sopenharmony_ci			return -EINVAL;
19778c2ecf20Sopenharmony_ci		}
19788c2ecf20Sopenharmony_ci		if  (addr <= limit)
19798c2ecf20Sopenharmony_ci			break;
19808c2ecf20Sopenharmony_ci		prv = limit;
19818c2ecf20Sopenharmony_ci	}
19828c2ecf20Sopenharmony_ci	if (n_sads == pvt->info.max_sad) {
19838c2ecf20Sopenharmony_ci		sprintf(msg, "Can't discover the memory socket");
19848c2ecf20Sopenharmony_ci		return -EINVAL;
19858c2ecf20Sopenharmony_ci	}
19868c2ecf20Sopenharmony_ci	dram_rule = reg;
19878c2ecf20Sopenharmony_ci	*area_type = show_dram_attr(pvt->info.dram_attr(dram_rule));
19888c2ecf20Sopenharmony_ci	interleave_mode = pvt->info.interleave_mode(dram_rule);
19898c2ecf20Sopenharmony_ci
19908c2ecf20Sopenharmony_ci	pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads],
19918c2ecf20Sopenharmony_ci			      &reg);
19928c2ecf20Sopenharmony_ci
19938c2ecf20Sopenharmony_ci	if (pvt->info.type == SANDY_BRIDGE) {
19948c2ecf20Sopenharmony_ci		sad_interl = sad_pkg(pvt->info.interleave_pkg, reg, 0);
19958c2ecf20Sopenharmony_ci		for (sad_way = 0; sad_way < 8; sad_way++) {
19968c2ecf20Sopenharmony_ci			u32 pkg = sad_pkg(pvt->info.interleave_pkg, reg, sad_way);
19978c2ecf20Sopenharmony_ci			if (sad_way > 0 && sad_interl == pkg)
19988c2ecf20Sopenharmony_ci				break;
19998c2ecf20Sopenharmony_ci			sad_interleave[sad_way] = pkg;
20008c2ecf20Sopenharmony_ci			edac_dbg(0, "SAD interleave #%d: %d\n",
20018c2ecf20Sopenharmony_ci				 sad_way, sad_interleave[sad_way]);
20028c2ecf20Sopenharmony_ci		}
20038c2ecf20Sopenharmony_ci		edac_dbg(0, "mc#%d: Error detected on SAD#%d: address 0x%016Lx < 0x%016Lx, Interleave [%d:6]%s\n",
20048c2ecf20Sopenharmony_ci			 pvt->sbridge_dev->mc,
20058c2ecf20Sopenharmony_ci			 n_sads,
20068c2ecf20Sopenharmony_ci			 addr,
20078c2ecf20Sopenharmony_ci			 limit,
20088c2ecf20Sopenharmony_ci			 sad_way + 7,
20098c2ecf20Sopenharmony_ci			 !interleave_mode ? "" : "XOR[18:16]");
20108c2ecf20Sopenharmony_ci		if (interleave_mode)
20118c2ecf20Sopenharmony_ci			idx = ((addr >> 6) ^ (addr >> 16)) & 7;
20128c2ecf20Sopenharmony_ci		else
20138c2ecf20Sopenharmony_ci			idx = (addr >> 6) & 7;
20148c2ecf20Sopenharmony_ci		switch (sad_way) {
20158c2ecf20Sopenharmony_ci		case 1:
20168c2ecf20Sopenharmony_ci			idx = 0;
20178c2ecf20Sopenharmony_ci			break;
20188c2ecf20Sopenharmony_ci		case 2:
20198c2ecf20Sopenharmony_ci			idx = idx & 1;
20208c2ecf20Sopenharmony_ci			break;
20218c2ecf20Sopenharmony_ci		case 4:
20228c2ecf20Sopenharmony_ci			idx = idx & 3;
20238c2ecf20Sopenharmony_ci			break;
20248c2ecf20Sopenharmony_ci		case 8:
20258c2ecf20Sopenharmony_ci			break;
20268c2ecf20Sopenharmony_ci		default:
20278c2ecf20Sopenharmony_ci			sprintf(msg, "Can't discover socket interleave");
20288c2ecf20Sopenharmony_ci			return -EINVAL;
20298c2ecf20Sopenharmony_ci		}
20308c2ecf20Sopenharmony_ci		*socket = sad_interleave[idx];
20318c2ecf20Sopenharmony_ci		edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n",
20328c2ecf20Sopenharmony_ci			 idx, sad_way, *socket);
20338c2ecf20Sopenharmony_ci	} else if (pvt->info.type == HASWELL || pvt->info.type == BROADWELL) {
20348c2ecf20Sopenharmony_ci		int bits, a7mode = A7MODE(dram_rule);
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci		if (a7mode) {
20378c2ecf20Sopenharmony_ci			/* A7 mode swaps P9 with P6 */
20388c2ecf20Sopenharmony_ci			bits = GET_BITFIELD(addr, 7, 8) << 1;
20398c2ecf20Sopenharmony_ci			bits |= GET_BITFIELD(addr, 9, 9);
20408c2ecf20Sopenharmony_ci		} else
20418c2ecf20Sopenharmony_ci			bits = GET_BITFIELD(addr, 6, 8);
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_ci		if (interleave_mode == 0) {
20448c2ecf20Sopenharmony_ci			/* interleave mode will XOR {8,7,6} with {18,17,16} */
20458c2ecf20Sopenharmony_ci			idx = GET_BITFIELD(addr, 16, 18);
20468c2ecf20Sopenharmony_ci			idx ^= bits;
20478c2ecf20Sopenharmony_ci		} else
20488c2ecf20Sopenharmony_ci			idx = bits;
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci		pkg = sad_pkg(pvt->info.interleave_pkg, reg, idx);
20518c2ecf20Sopenharmony_ci		*socket = sad_pkg_socket(pkg);
20528c2ecf20Sopenharmony_ci		sad_ha = sad_pkg_ha(pkg);
20538c2ecf20Sopenharmony_ci
20548c2ecf20Sopenharmony_ci		if (a7mode) {
20558c2ecf20Sopenharmony_ci			/* MCChanShiftUpEnable */
20568c2ecf20Sopenharmony_ci			pci_read_config_dword(pvt->pci_ha, HASWELL_HASYSDEFEATURE2, &reg);
20578c2ecf20Sopenharmony_ci			shiftup = GET_BITFIELD(reg, 22, 22);
20588c2ecf20Sopenharmony_ci		}
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_ci		edac_dbg(0, "SAD interleave package: %d = CPU socket %d, HA %i, shiftup: %i\n",
20618c2ecf20Sopenharmony_ci			 idx, *socket, sad_ha, shiftup);
20628c2ecf20Sopenharmony_ci	} else {
20638c2ecf20Sopenharmony_ci		/* Ivy Bridge's SAD mode doesn't support XOR interleave mode */
20648c2ecf20Sopenharmony_ci		idx = (addr >> 6) & 7;
20658c2ecf20Sopenharmony_ci		pkg = sad_pkg(pvt->info.interleave_pkg, reg, idx);
20668c2ecf20Sopenharmony_ci		*socket = sad_pkg_socket(pkg);
20678c2ecf20Sopenharmony_ci		sad_ha = sad_pkg_ha(pkg);
20688c2ecf20Sopenharmony_ci		edac_dbg(0, "SAD interleave package: %d = CPU socket %d, HA %d\n",
20698c2ecf20Sopenharmony_ci			 idx, *socket, sad_ha);
20708c2ecf20Sopenharmony_ci	}
20718c2ecf20Sopenharmony_ci
20728c2ecf20Sopenharmony_ci	*ha = sad_ha;
20738c2ecf20Sopenharmony_ci
20748c2ecf20Sopenharmony_ci	/*
20758c2ecf20Sopenharmony_ci	 * Move to the proper node structure, in order to access the
20768c2ecf20Sopenharmony_ci	 * right PCI registers
20778c2ecf20Sopenharmony_ci	 */
20788c2ecf20Sopenharmony_ci	new_mci = get_mci_for_node_id(*socket, sad_ha);
20798c2ecf20Sopenharmony_ci	if (!new_mci) {
20808c2ecf20Sopenharmony_ci		sprintf(msg, "Struct for socket #%u wasn't initialized",
20818c2ecf20Sopenharmony_ci			*socket);
20828c2ecf20Sopenharmony_ci		return -EINVAL;
20838c2ecf20Sopenharmony_ci	}
20848c2ecf20Sopenharmony_ci	mci = new_mci;
20858c2ecf20Sopenharmony_ci	pvt = mci->pvt_info;
20868c2ecf20Sopenharmony_ci
20878c2ecf20Sopenharmony_ci	/*
20888c2ecf20Sopenharmony_ci	 * Step 2) Get memory channel
20898c2ecf20Sopenharmony_ci	 */
20908c2ecf20Sopenharmony_ci	prv = 0;
20918c2ecf20Sopenharmony_ci	pci_ha = pvt->pci_ha;
20928c2ecf20Sopenharmony_ci	for (n_tads = 0; n_tads < MAX_TAD; n_tads++) {
20938c2ecf20Sopenharmony_ci		pci_read_config_dword(pci_ha, tad_dram_rule[n_tads], &reg);
20948c2ecf20Sopenharmony_ci		limit = TAD_LIMIT(reg);
20958c2ecf20Sopenharmony_ci		if (limit <= prv) {
20968c2ecf20Sopenharmony_ci			sprintf(msg, "Can't discover the memory channel");
20978c2ecf20Sopenharmony_ci			return -EINVAL;
20988c2ecf20Sopenharmony_ci		}
20998c2ecf20Sopenharmony_ci		if  (addr <= limit)
21008c2ecf20Sopenharmony_ci			break;
21018c2ecf20Sopenharmony_ci		prv = limit;
21028c2ecf20Sopenharmony_ci	}
21038c2ecf20Sopenharmony_ci	if (n_tads == MAX_TAD) {
21048c2ecf20Sopenharmony_ci		sprintf(msg, "Can't discover the memory channel");
21058c2ecf20Sopenharmony_ci		return -EINVAL;
21068c2ecf20Sopenharmony_ci	}
21078c2ecf20Sopenharmony_ci
21088c2ecf20Sopenharmony_ci	ch_way = TAD_CH(reg) + 1;
21098c2ecf20Sopenharmony_ci	sck_way = TAD_SOCK(reg);
21108c2ecf20Sopenharmony_ci
21118c2ecf20Sopenharmony_ci	if (ch_way == 3)
21128c2ecf20Sopenharmony_ci		idx = addr >> 6;
21138c2ecf20Sopenharmony_ci	else {
21148c2ecf20Sopenharmony_ci		idx = (addr >> (6 + sck_way + shiftup)) & 0x3;
21158c2ecf20Sopenharmony_ci		if (pvt->is_chan_hash)
21168c2ecf20Sopenharmony_ci			idx = haswell_chan_hash(idx, addr);
21178c2ecf20Sopenharmony_ci	}
21188c2ecf20Sopenharmony_ci	idx = idx % ch_way;
21198c2ecf20Sopenharmony_ci
21208c2ecf20Sopenharmony_ci	/*
21218c2ecf20Sopenharmony_ci	 * FIXME: Shouldn't we use CHN_IDX_OFFSET() here, when ch_way == 3 ???
21228c2ecf20Sopenharmony_ci	 */
21238c2ecf20Sopenharmony_ci	switch (idx) {
21248c2ecf20Sopenharmony_ci	case 0:
21258c2ecf20Sopenharmony_ci		base_ch = TAD_TGT0(reg);
21268c2ecf20Sopenharmony_ci		break;
21278c2ecf20Sopenharmony_ci	case 1:
21288c2ecf20Sopenharmony_ci		base_ch = TAD_TGT1(reg);
21298c2ecf20Sopenharmony_ci		break;
21308c2ecf20Sopenharmony_ci	case 2:
21318c2ecf20Sopenharmony_ci		base_ch = TAD_TGT2(reg);
21328c2ecf20Sopenharmony_ci		break;
21338c2ecf20Sopenharmony_ci	case 3:
21348c2ecf20Sopenharmony_ci		base_ch = TAD_TGT3(reg);
21358c2ecf20Sopenharmony_ci		break;
21368c2ecf20Sopenharmony_ci	default:
21378c2ecf20Sopenharmony_ci		sprintf(msg, "Can't discover the TAD target");
21388c2ecf20Sopenharmony_ci		return -EINVAL;
21398c2ecf20Sopenharmony_ci	}
21408c2ecf20Sopenharmony_ci	*channel_mask = 1 << base_ch;
21418c2ecf20Sopenharmony_ci
21428c2ecf20Sopenharmony_ci	pci_read_config_dword(pvt->pci_tad[base_ch], tad_ch_nilv_offset[n_tads], &tad_offset);
21438c2ecf20Sopenharmony_ci
21448c2ecf20Sopenharmony_ci	if (pvt->mirror_mode == FULL_MIRRORING ||
21458c2ecf20Sopenharmony_ci	    (pvt->mirror_mode == ADDR_RANGE_MIRRORING && n_tads == 0)) {
21468c2ecf20Sopenharmony_ci		*channel_mask |= 1 << ((base_ch + 2) % 4);
21478c2ecf20Sopenharmony_ci		switch(ch_way) {
21488c2ecf20Sopenharmony_ci		case 2:
21498c2ecf20Sopenharmony_ci		case 4:
21508c2ecf20Sopenharmony_ci			sck_xch = (1 << sck_way) * (ch_way >> 1);
21518c2ecf20Sopenharmony_ci			break;
21528c2ecf20Sopenharmony_ci		default:
21538c2ecf20Sopenharmony_ci			sprintf(msg, "Invalid mirror set. Can't decode addr");
21548c2ecf20Sopenharmony_ci			return -EINVAL;
21558c2ecf20Sopenharmony_ci		}
21568c2ecf20Sopenharmony_ci
21578c2ecf20Sopenharmony_ci		pvt->is_cur_addr_mirrored = true;
21588c2ecf20Sopenharmony_ci	} else {
21598c2ecf20Sopenharmony_ci		sck_xch = (1 << sck_way) * ch_way;
21608c2ecf20Sopenharmony_ci		pvt->is_cur_addr_mirrored = false;
21618c2ecf20Sopenharmony_ci	}
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_ci	if (pvt->is_lockstep)
21648c2ecf20Sopenharmony_ci		*channel_mask |= 1 << ((base_ch + 1) % 4);
21658c2ecf20Sopenharmony_ci
21668c2ecf20Sopenharmony_ci	offset = TAD_OFFSET(tad_offset);
21678c2ecf20Sopenharmony_ci
21688c2ecf20Sopenharmony_ci	edac_dbg(0, "TAD#%d: address 0x%016Lx < 0x%016Lx, socket interleave %d, channel interleave %d (offset 0x%08Lx), index %d, base ch: %d, ch mask: 0x%02lx\n",
21698c2ecf20Sopenharmony_ci		 n_tads,
21708c2ecf20Sopenharmony_ci		 addr,
21718c2ecf20Sopenharmony_ci		 limit,
21728c2ecf20Sopenharmony_ci		 sck_way,
21738c2ecf20Sopenharmony_ci		 ch_way,
21748c2ecf20Sopenharmony_ci		 offset,
21758c2ecf20Sopenharmony_ci		 idx,
21768c2ecf20Sopenharmony_ci		 base_ch,
21778c2ecf20Sopenharmony_ci		 *channel_mask);
21788c2ecf20Sopenharmony_ci
21798c2ecf20Sopenharmony_ci	/* Calculate channel address */
21808c2ecf20Sopenharmony_ci	/* Remove the TAD offset */
21818c2ecf20Sopenharmony_ci
21828c2ecf20Sopenharmony_ci	if (offset > addr) {
21838c2ecf20Sopenharmony_ci		sprintf(msg, "Can't calculate ch addr: TAD offset 0x%08Lx is too high for addr 0x%08Lx!",
21848c2ecf20Sopenharmony_ci			offset, addr);
21858c2ecf20Sopenharmony_ci		return -EINVAL;
21868c2ecf20Sopenharmony_ci	}
21878c2ecf20Sopenharmony_ci
21888c2ecf20Sopenharmony_ci	ch_addr = addr - offset;
21898c2ecf20Sopenharmony_ci	ch_addr >>= (6 + shiftup);
21908c2ecf20Sopenharmony_ci	ch_addr /= sck_xch;
21918c2ecf20Sopenharmony_ci	ch_addr <<= (6 + shiftup);
21928c2ecf20Sopenharmony_ci	ch_addr |= addr & ((1 << (6 + shiftup)) - 1);
21938c2ecf20Sopenharmony_ci
21948c2ecf20Sopenharmony_ci	/*
21958c2ecf20Sopenharmony_ci	 * Step 3) Decode rank
21968c2ecf20Sopenharmony_ci	 */
21978c2ecf20Sopenharmony_ci	for (n_rir = 0; n_rir < MAX_RIR_RANGES; n_rir++) {
21988c2ecf20Sopenharmony_ci		pci_read_config_dword(pvt->pci_tad[base_ch], rir_way_limit[n_rir], &reg);
21998c2ecf20Sopenharmony_ci
22008c2ecf20Sopenharmony_ci		if (!IS_RIR_VALID(reg))
22018c2ecf20Sopenharmony_ci			continue;
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_ci		limit = pvt->info.rir_limit(reg);
22048c2ecf20Sopenharmony_ci		gb = div_u64_rem(limit >> 20, 1024, &mb);
22058c2ecf20Sopenharmony_ci		edac_dbg(0, "RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d\n",
22068c2ecf20Sopenharmony_ci			 n_rir,
22078c2ecf20Sopenharmony_ci			 gb, (mb*1000)/1024,
22088c2ecf20Sopenharmony_ci			 limit,
22098c2ecf20Sopenharmony_ci			 1 << RIR_WAY(reg));
22108c2ecf20Sopenharmony_ci		if  (ch_addr <= limit)
22118c2ecf20Sopenharmony_ci			break;
22128c2ecf20Sopenharmony_ci	}
22138c2ecf20Sopenharmony_ci	if (n_rir == MAX_RIR_RANGES) {
22148c2ecf20Sopenharmony_ci		sprintf(msg, "Can't discover the memory rank for ch addr 0x%08Lx",
22158c2ecf20Sopenharmony_ci			ch_addr);
22168c2ecf20Sopenharmony_ci		return -EINVAL;
22178c2ecf20Sopenharmony_ci	}
22188c2ecf20Sopenharmony_ci	rir_way = RIR_WAY(reg);
22198c2ecf20Sopenharmony_ci
22208c2ecf20Sopenharmony_ci	if (pvt->is_close_pg)
22218c2ecf20Sopenharmony_ci		idx = (ch_addr >> 6);
22228c2ecf20Sopenharmony_ci	else
22238c2ecf20Sopenharmony_ci		idx = (ch_addr >> 13);	/* FIXME: Datasheet says to shift by 15 */
22248c2ecf20Sopenharmony_ci	idx %= 1 << rir_way;
22258c2ecf20Sopenharmony_ci
22268c2ecf20Sopenharmony_ci	pci_read_config_dword(pvt->pci_tad[base_ch], rir_offset[n_rir][idx], &reg);
22278c2ecf20Sopenharmony_ci	*rank = RIR_RNK_TGT(pvt->info.type, reg);
22288c2ecf20Sopenharmony_ci
22298c2ecf20Sopenharmony_ci	edac_dbg(0, "RIR#%d: channel address 0x%08Lx < 0x%08Lx, RIR interleave %d, index %d\n",
22308c2ecf20Sopenharmony_ci		 n_rir,
22318c2ecf20Sopenharmony_ci		 ch_addr,
22328c2ecf20Sopenharmony_ci		 limit,
22338c2ecf20Sopenharmony_ci		 rir_way,
22348c2ecf20Sopenharmony_ci		 idx);
22358c2ecf20Sopenharmony_ci
22368c2ecf20Sopenharmony_ci	return 0;
22378c2ecf20Sopenharmony_ci}
22388c2ecf20Sopenharmony_ci
22398c2ecf20Sopenharmony_cistatic int get_memory_error_data_from_mce(struct mem_ctl_info *mci,
22408c2ecf20Sopenharmony_ci					  const struct mce *m, u8 *socket,
22418c2ecf20Sopenharmony_ci					  u8 *ha, long *channel_mask,
22428c2ecf20Sopenharmony_ci					  char *msg)
22438c2ecf20Sopenharmony_ci{
22448c2ecf20Sopenharmony_ci	u32 reg, channel = GET_BITFIELD(m->status, 0, 3);
22458c2ecf20Sopenharmony_ci	struct mem_ctl_info *new_mci;
22468c2ecf20Sopenharmony_ci	struct sbridge_pvt *pvt;
22478c2ecf20Sopenharmony_ci	struct pci_dev *pci_ha;
22488c2ecf20Sopenharmony_ci	bool tad0;
22498c2ecf20Sopenharmony_ci
22508c2ecf20Sopenharmony_ci	if (channel >= NUM_CHANNELS) {
22518c2ecf20Sopenharmony_ci		sprintf(msg, "Invalid channel 0x%x", channel);
22528c2ecf20Sopenharmony_ci		return -EINVAL;
22538c2ecf20Sopenharmony_ci	}
22548c2ecf20Sopenharmony_ci
22558c2ecf20Sopenharmony_ci	pvt = mci->pvt_info;
22568c2ecf20Sopenharmony_ci	if (!pvt->info.get_ha) {
22578c2ecf20Sopenharmony_ci		sprintf(msg, "No get_ha()");
22588c2ecf20Sopenharmony_ci		return -EINVAL;
22598c2ecf20Sopenharmony_ci	}
22608c2ecf20Sopenharmony_ci	*ha = pvt->info.get_ha(m->bank);
22618c2ecf20Sopenharmony_ci	if (*ha != 0 && *ha != 1) {
22628c2ecf20Sopenharmony_ci		sprintf(msg, "Impossible bank %d", m->bank);
22638c2ecf20Sopenharmony_ci		return -EINVAL;
22648c2ecf20Sopenharmony_ci	}
22658c2ecf20Sopenharmony_ci
22668c2ecf20Sopenharmony_ci	*socket = m->socketid;
22678c2ecf20Sopenharmony_ci	new_mci = get_mci_for_node_id(*socket, *ha);
22688c2ecf20Sopenharmony_ci	if (!new_mci) {
22698c2ecf20Sopenharmony_ci		strcpy(msg, "mci socket got corrupted!");
22708c2ecf20Sopenharmony_ci		return -EINVAL;
22718c2ecf20Sopenharmony_ci	}
22728c2ecf20Sopenharmony_ci
22738c2ecf20Sopenharmony_ci	pvt = new_mci->pvt_info;
22748c2ecf20Sopenharmony_ci	pci_ha = pvt->pci_ha;
22758c2ecf20Sopenharmony_ci	pci_read_config_dword(pci_ha, tad_dram_rule[0], &reg);
22768c2ecf20Sopenharmony_ci	tad0 = m->addr <= TAD_LIMIT(reg);
22778c2ecf20Sopenharmony_ci
22788c2ecf20Sopenharmony_ci	*channel_mask = 1 << channel;
22798c2ecf20Sopenharmony_ci	if (pvt->mirror_mode == FULL_MIRRORING ||
22808c2ecf20Sopenharmony_ci	    (pvt->mirror_mode == ADDR_RANGE_MIRRORING && tad0)) {
22818c2ecf20Sopenharmony_ci		*channel_mask |= 1 << ((channel + 2) % 4);
22828c2ecf20Sopenharmony_ci		pvt->is_cur_addr_mirrored = true;
22838c2ecf20Sopenharmony_ci	} else {
22848c2ecf20Sopenharmony_ci		pvt->is_cur_addr_mirrored = false;
22858c2ecf20Sopenharmony_ci	}
22868c2ecf20Sopenharmony_ci
22878c2ecf20Sopenharmony_ci	if (pvt->is_lockstep)
22888c2ecf20Sopenharmony_ci		*channel_mask |= 1 << ((channel + 1) % 4);
22898c2ecf20Sopenharmony_ci
22908c2ecf20Sopenharmony_ci	return 0;
22918c2ecf20Sopenharmony_ci}
22928c2ecf20Sopenharmony_ci
22938c2ecf20Sopenharmony_ci/****************************************************************************
22948c2ecf20Sopenharmony_ci	Device initialization routines: put/get, init/exit
22958c2ecf20Sopenharmony_ci ****************************************************************************/
22968c2ecf20Sopenharmony_ci
22978c2ecf20Sopenharmony_ci/*
22988c2ecf20Sopenharmony_ci *	sbridge_put_all_devices	'put' all the devices that we have
22998c2ecf20Sopenharmony_ci *				reserved via 'get'
23008c2ecf20Sopenharmony_ci */
23018c2ecf20Sopenharmony_cistatic void sbridge_put_devices(struct sbridge_dev *sbridge_dev)
23028c2ecf20Sopenharmony_ci{
23038c2ecf20Sopenharmony_ci	int i;
23048c2ecf20Sopenharmony_ci
23058c2ecf20Sopenharmony_ci	edac_dbg(0, "\n");
23068c2ecf20Sopenharmony_ci	for (i = 0; i < sbridge_dev->n_devs; i++) {
23078c2ecf20Sopenharmony_ci		struct pci_dev *pdev = sbridge_dev->pdev[i];
23088c2ecf20Sopenharmony_ci		if (!pdev)
23098c2ecf20Sopenharmony_ci			continue;
23108c2ecf20Sopenharmony_ci		edac_dbg(0, "Removing dev %02x:%02x.%d\n",
23118c2ecf20Sopenharmony_ci			 pdev->bus->number,
23128c2ecf20Sopenharmony_ci			 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
23138c2ecf20Sopenharmony_ci		pci_dev_put(pdev);
23148c2ecf20Sopenharmony_ci	}
23158c2ecf20Sopenharmony_ci}
23168c2ecf20Sopenharmony_ci
23178c2ecf20Sopenharmony_cistatic void sbridge_put_all_devices(void)
23188c2ecf20Sopenharmony_ci{
23198c2ecf20Sopenharmony_ci	struct sbridge_dev *sbridge_dev, *tmp;
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci	list_for_each_entry_safe(sbridge_dev, tmp, &sbridge_edac_list, list) {
23228c2ecf20Sopenharmony_ci		sbridge_put_devices(sbridge_dev);
23238c2ecf20Sopenharmony_ci		free_sbridge_dev(sbridge_dev);
23248c2ecf20Sopenharmony_ci	}
23258c2ecf20Sopenharmony_ci}
23268c2ecf20Sopenharmony_ci
23278c2ecf20Sopenharmony_cistatic int sbridge_get_onedevice(struct pci_dev **prev,
23288c2ecf20Sopenharmony_ci				 u8 *num_mc,
23298c2ecf20Sopenharmony_ci				 const struct pci_id_table *table,
23308c2ecf20Sopenharmony_ci				 const unsigned devno,
23318c2ecf20Sopenharmony_ci				 const int multi_bus)
23328c2ecf20Sopenharmony_ci{
23338c2ecf20Sopenharmony_ci	struct sbridge_dev *sbridge_dev = NULL;
23348c2ecf20Sopenharmony_ci	const struct pci_id_descr *dev_descr = &table->descr[devno];
23358c2ecf20Sopenharmony_ci	struct pci_dev *pdev = NULL;
23368c2ecf20Sopenharmony_ci	int seg = 0;
23378c2ecf20Sopenharmony_ci	u8 bus = 0;
23388c2ecf20Sopenharmony_ci	int i = 0;
23398c2ecf20Sopenharmony_ci
23408c2ecf20Sopenharmony_ci	sbridge_printk(KERN_DEBUG,
23418c2ecf20Sopenharmony_ci		"Seeking for: PCI ID %04x:%04x\n",
23428c2ecf20Sopenharmony_ci		PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
23438c2ecf20Sopenharmony_ci
23448c2ecf20Sopenharmony_ci	pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
23458c2ecf20Sopenharmony_ci			      dev_descr->dev_id, *prev);
23468c2ecf20Sopenharmony_ci
23478c2ecf20Sopenharmony_ci	if (!pdev) {
23488c2ecf20Sopenharmony_ci		if (*prev) {
23498c2ecf20Sopenharmony_ci			*prev = pdev;
23508c2ecf20Sopenharmony_ci			return 0;
23518c2ecf20Sopenharmony_ci		}
23528c2ecf20Sopenharmony_ci
23538c2ecf20Sopenharmony_ci		if (dev_descr->optional)
23548c2ecf20Sopenharmony_ci			return 0;
23558c2ecf20Sopenharmony_ci
23568c2ecf20Sopenharmony_ci		/* if the HA wasn't found */
23578c2ecf20Sopenharmony_ci		if (devno == 0)
23588c2ecf20Sopenharmony_ci			return -ENODEV;
23598c2ecf20Sopenharmony_ci
23608c2ecf20Sopenharmony_ci		sbridge_printk(KERN_INFO,
23618c2ecf20Sopenharmony_ci			"Device not found: %04x:%04x\n",
23628c2ecf20Sopenharmony_ci			PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
23638c2ecf20Sopenharmony_ci
23648c2ecf20Sopenharmony_ci		/* End of list, leave */
23658c2ecf20Sopenharmony_ci		return -ENODEV;
23668c2ecf20Sopenharmony_ci	}
23678c2ecf20Sopenharmony_ci	seg = pci_domain_nr(pdev->bus);
23688c2ecf20Sopenharmony_ci	bus = pdev->bus->number;
23698c2ecf20Sopenharmony_ci
23708c2ecf20Sopenharmony_cinext_imc:
23718c2ecf20Sopenharmony_ci	sbridge_dev = get_sbridge_dev(seg, bus, dev_descr->dom,
23728c2ecf20Sopenharmony_ci				      multi_bus, sbridge_dev);
23738c2ecf20Sopenharmony_ci	if (!sbridge_dev) {
23748c2ecf20Sopenharmony_ci		/* If the HA1 wasn't found, don't create EDAC second memory controller */
23758c2ecf20Sopenharmony_ci		if (dev_descr->dom == IMC1 && devno != 1) {
23768c2ecf20Sopenharmony_ci			edac_dbg(0, "Skip IMC1: %04x:%04x (since HA1 was absent)\n",
23778c2ecf20Sopenharmony_ci				 PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
23788c2ecf20Sopenharmony_ci			pci_dev_put(pdev);
23798c2ecf20Sopenharmony_ci			return 0;
23808c2ecf20Sopenharmony_ci		}
23818c2ecf20Sopenharmony_ci
23828c2ecf20Sopenharmony_ci		if (dev_descr->dom == SOCK)
23838c2ecf20Sopenharmony_ci			goto out_imc;
23848c2ecf20Sopenharmony_ci
23858c2ecf20Sopenharmony_ci		sbridge_dev = alloc_sbridge_dev(seg, bus, dev_descr->dom, table);
23868c2ecf20Sopenharmony_ci		if (!sbridge_dev) {
23878c2ecf20Sopenharmony_ci			pci_dev_put(pdev);
23888c2ecf20Sopenharmony_ci			return -ENOMEM;
23898c2ecf20Sopenharmony_ci		}
23908c2ecf20Sopenharmony_ci		(*num_mc)++;
23918c2ecf20Sopenharmony_ci	}
23928c2ecf20Sopenharmony_ci
23938c2ecf20Sopenharmony_ci	if (sbridge_dev->pdev[sbridge_dev->i_devs]) {
23948c2ecf20Sopenharmony_ci		sbridge_printk(KERN_ERR,
23958c2ecf20Sopenharmony_ci			"Duplicated device for %04x:%04x\n",
23968c2ecf20Sopenharmony_ci			PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
23978c2ecf20Sopenharmony_ci		pci_dev_put(pdev);
23988c2ecf20Sopenharmony_ci		return -ENODEV;
23998c2ecf20Sopenharmony_ci	}
24008c2ecf20Sopenharmony_ci
24018c2ecf20Sopenharmony_ci	sbridge_dev->pdev[sbridge_dev->i_devs++] = pdev;
24028c2ecf20Sopenharmony_ci
24038c2ecf20Sopenharmony_ci	/* pdev belongs to more than one IMC, do extra gets */
24048c2ecf20Sopenharmony_ci	if (++i > 1)
24058c2ecf20Sopenharmony_ci		pci_dev_get(pdev);
24068c2ecf20Sopenharmony_ci
24078c2ecf20Sopenharmony_ci	if (dev_descr->dom == SOCK && i < table->n_imcs_per_sock)
24088c2ecf20Sopenharmony_ci		goto next_imc;
24098c2ecf20Sopenharmony_ci
24108c2ecf20Sopenharmony_ciout_imc:
24118c2ecf20Sopenharmony_ci	/* Be sure that the device is enabled */
24128c2ecf20Sopenharmony_ci	if (unlikely(pci_enable_device(pdev) < 0)) {
24138c2ecf20Sopenharmony_ci		sbridge_printk(KERN_ERR,
24148c2ecf20Sopenharmony_ci			"Couldn't enable %04x:%04x\n",
24158c2ecf20Sopenharmony_ci			PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
24168c2ecf20Sopenharmony_ci		return -ENODEV;
24178c2ecf20Sopenharmony_ci	}
24188c2ecf20Sopenharmony_ci
24198c2ecf20Sopenharmony_ci	edac_dbg(0, "Detected %04x:%04x\n",
24208c2ecf20Sopenharmony_ci		 PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
24218c2ecf20Sopenharmony_ci
24228c2ecf20Sopenharmony_ci	/*
24238c2ecf20Sopenharmony_ci	 * As stated on drivers/pci/search.c, the reference count for
24248c2ecf20Sopenharmony_ci	 * @from is always decremented if it is not %NULL. So, as we need
24258c2ecf20Sopenharmony_ci	 * to get all devices up to null, we need to do a get for the device
24268c2ecf20Sopenharmony_ci	 */
24278c2ecf20Sopenharmony_ci	pci_dev_get(pdev);
24288c2ecf20Sopenharmony_ci
24298c2ecf20Sopenharmony_ci	*prev = pdev;
24308c2ecf20Sopenharmony_ci
24318c2ecf20Sopenharmony_ci	return 0;
24328c2ecf20Sopenharmony_ci}
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_ci/*
24358c2ecf20Sopenharmony_ci * sbridge_get_all_devices - Find and perform 'get' operation on the MCH's
24368c2ecf20Sopenharmony_ci *			     devices we want to reference for this driver.
24378c2ecf20Sopenharmony_ci * @num_mc: pointer to the memory controllers count, to be incremented in case
24388c2ecf20Sopenharmony_ci *	    of success.
24398c2ecf20Sopenharmony_ci * @table: model specific table
24408c2ecf20Sopenharmony_ci *
24418c2ecf20Sopenharmony_ci * returns 0 in case of success or error code
24428c2ecf20Sopenharmony_ci */
24438c2ecf20Sopenharmony_cistatic int sbridge_get_all_devices(u8 *num_mc,
24448c2ecf20Sopenharmony_ci					const struct pci_id_table *table)
24458c2ecf20Sopenharmony_ci{
24468c2ecf20Sopenharmony_ci	int i, rc;
24478c2ecf20Sopenharmony_ci	struct pci_dev *pdev = NULL;
24488c2ecf20Sopenharmony_ci	int allow_dups = 0;
24498c2ecf20Sopenharmony_ci	int multi_bus = 0;
24508c2ecf20Sopenharmony_ci
24518c2ecf20Sopenharmony_ci	if (table->type == KNIGHTS_LANDING)
24528c2ecf20Sopenharmony_ci		allow_dups = multi_bus = 1;
24538c2ecf20Sopenharmony_ci	while (table && table->descr) {
24548c2ecf20Sopenharmony_ci		for (i = 0; i < table->n_devs_per_sock; i++) {
24558c2ecf20Sopenharmony_ci			if (!allow_dups || i == 0 ||
24568c2ecf20Sopenharmony_ci					table->descr[i].dev_id !=
24578c2ecf20Sopenharmony_ci						table->descr[i-1].dev_id) {
24588c2ecf20Sopenharmony_ci				pdev = NULL;
24598c2ecf20Sopenharmony_ci			}
24608c2ecf20Sopenharmony_ci			do {
24618c2ecf20Sopenharmony_ci				rc = sbridge_get_onedevice(&pdev, num_mc,
24628c2ecf20Sopenharmony_ci							   table, i, multi_bus);
24638c2ecf20Sopenharmony_ci				if (rc < 0) {
24648c2ecf20Sopenharmony_ci					if (i == 0) {
24658c2ecf20Sopenharmony_ci						i = table->n_devs_per_sock;
24668c2ecf20Sopenharmony_ci						break;
24678c2ecf20Sopenharmony_ci					}
24688c2ecf20Sopenharmony_ci					sbridge_put_all_devices();
24698c2ecf20Sopenharmony_ci					return -ENODEV;
24708c2ecf20Sopenharmony_ci				}
24718c2ecf20Sopenharmony_ci			} while (pdev && !allow_dups);
24728c2ecf20Sopenharmony_ci		}
24738c2ecf20Sopenharmony_ci		table++;
24748c2ecf20Sopenharmony_ci	}
24758c2ecf20Sopenharmony_ci
24768c2ecf20Sopenharmony_ci	return 0;
24778c2ecf20Sopenharmony_ci}
24788c2ecf20Sopenharmony_ci
24798c2ecf20Sopenharmony_ci/*
24808c2ecf20Sopenharmony_ci * Device IDs for {SBRIDGE,IBRIDGE,HASWELL,BROADWELL}_IMC_HA0_TAD0 are in
24818c2ecf20Sopenharmony_ci * the format: XXXa. So we can convert from a device to the corresponding
24828c2ecf20Sopenharmony_ci * channel like this
24838c2ecf20Sopenharmony_ci */
24848c2ecf20Sopenharmony_ci#define TAD_DEV_TO_CHAN(dev) (((dev) & 0xf) - 0xa)
24858c2ecf20Sopenharmony_ci
24868c2ecf20Sopenharmony_cistatic int sbridge_mci_bind_devs(struct mem_ctl_info *mci,
24878c2ecf20Sopenharmony_ci				 struct sbridge_dev *sbridge_dev)
24888c2ecf20Sopenharmony_ci{
24898c2ecf20Sopenharmony_ci	struct sbridge_pvt *pvt = mci->pvt_info;
24908c2ecf20Sopenharmony_ci	struct pci_dev *pdev;
24918c2ecf20Sopenharmony_ci	u8 saw_chan_mask = 0;
24928c2ecf20Sopenharmony_ci	int i;
24938c2ecf20Sopenharmony_ci
24948c2ecf20Sopenharmony_ci	for (i = 0; i < sbridge_dev->n_devs; i++) {
24958c2ecf20Sopenharmony_ci		pdev = sbridge_dev->pdev[i];
24968c2ecf20Sopenharmony_ci		if (!pdev)
24978c2ecf20Sopenharmony_ci			continue;
24988c2ecf20Sopenharmony_ci
24998c2ecf20Sopenharmony_ci		switch (pdev->device) {
25008c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0:
25018c2ecf20Sopenharmony_ci			pvt->pci_sad0 = pdev;
25028c2ecf20Sopenharmony_ci			break;
25038c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1:
25048c2ecf20Sopenharmony_ci			pvt->pci_sad1 = pdev;
25058c2ecf20Sopenharmony_ci			break;
25068c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_SBRIDGE_BR:
25078c2ecf20Sopenharmony_ci			pvt->pci_br0 = pdev;
25088c2ecf20Sopenharmony_ci			break;
25098c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0:
25108c2ecf20Sopenharmony_ci			pvt->pci_ha = pdev;
25118c2ecf20Sopenharmony_ci			break;
25128c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA:
25138c2ecf20Sopenharmony_ci			pvt->pci_ta = pdev;
25148c2ecf20Sopenharmony_ci			break;
25158c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS:
25168c2ecf20Sopenharmony_ci			pvt->pci_ras = pdev;
25178c2ecf20Sopenharmony_ci			break;
25188c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0:
25198c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1:
25208c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2:
25218c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3:
25228c2ecf20Sopenharmony_ci		{
25238c2ecf20Sopenharmony_ci			int id = TAD_DEV_TO_CHAN(pdev->device);
25248c2ecf20Sopenharmony_ci			pvt->pci_tad[id] = pdev;
25258c2ecf20Sopenharmony_ci			saw_chan_mask |= 1 << id;
25268c2ecf20Sopenharmony_ci		}
25278c2ecf20Sopenharmony_ci			break;
25288c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO:
25298c2ecf20Sopenharmony_ci			pvt->pci_ddrio = pdev;
25308c2ecf20Sopenharmony_ci			break;
25318c2ecf20Sopenharmony_ci		default:
25328c2ecf20Sopenharmony_ci			goto error;
25338c2ecf20Sopenharmony_ci		}
25348c2ecf20Sopenharmony_ci
25358c2ecf20Sopenharmony_ci		edac_dbg(0, "Associated PCI %02x:%02x, bus %d with dev = %p\n",
25368c2ecf20Sopenharmony_ci			 pdev->vendor, pdev->device,
25378c2ecf20Sopenharmony_ci			 sbridge_dev->bus,
25388c2ecf20Sopenharmony_ci			 pdev);
25398c2ecf20Sopenharmony_ci	}
25408c2ecf20Sopenharmony_ci
25418c2ecf20Sopenharmony_ci	/* Check if everything were registered */
25428c2ecf20Sopenharmony_ci	if (!pvt->pci_sad0 || !pvt->pci_sad1 || !pvt->pci_ha ||
25438c2ecf20Sopenharmony_ci	    !pvt->pci_ras || !pvt->pci_ta)
25448c2ecf20Sopenharmony_ci		goto enodev;
25458c2ecf20Sopenharmony_ci
25468c2ecf20Sopenharmony_ci	if (saw_chan_mask != 0x0f)
25478c2ecf20Sopenharmony_ci		goto enodev;
25488c2ecf20Sopenharmony_ci	return 0;
25498c2ecf20Sopenharmony_ci
25508c2ecf20Sopenharmony_cienodev:
25518c2ecf20Sopenharmony_ci	sbridge_printk(KERN_ERR, "Some needed devices are missing\n");
25528c2ecf20Sopenharmony_ci	return -ENODEV;
25538c2ecf20Sopenharmony_ci
25548c2ecf20Sopenharmony_cierror:
25558c2ecf20Sopenharmony_ci	sbridge_printk(KERN_ERR, "Unexpected device %02x:%02x\n",
25568c2ecf20Sopenharmony_ci		       PCI_VENDOR_ID_INTEL, pdev->device);
25578c2ecf20Sopenharmony_ci	return -EINVAL;
25588c2ecf20Sopenharmony_ci}
25598c2ecf20Sopenharmony_ci
25608c2ecf20Sopenharmony_cistatic int ibridge_mci_bind_devs(struct mem_ctl_info *mci,
25618c2ecf20Sopenharmony_ci				 struct sbridge_dev *sbridge_dev)
25628c2ecf20Sopenharmony_ci{
25638c2ecf20Sopenharmony_ci	struct sbridge_pvt *pvt = mci->pvt_info;
25648c2ecf20Sopenharmony_ci	struct pci_dev *pdev;
25658c2ecf20Sopenharmony_ci	u8 saw_chan_mask = 0;
25668c2ecf20Sopenharmony_ci	int i;
25678c2ecf20Sopenharmony_ci
25688c2ecf20Sopenharmony_ci	for (i = 0; i < sbridge_dev->n_devs; i++) {
25698c2ecf20Sopenharmony_ci		pdev = sbridge_dev->pdev[i];
25708c2ecf20Sopenharmony_ci		if (!pdev)
25718c2ecf20Sopenharmony_ci			continue;
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_ci		switch (pdev->device) {
25748c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0:
25758c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1:
25768c2ecf20Sopenharmony_ci			pvt->pci_ha = pdev;
25778c2ecf20Sopenharmony_ci			break;
25788c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA:
25798c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA:
25808c2ecf20Sopenharmony_ci			pvt->pci_ta = pdev;
25818c2ecf20Sopenharmony_ci			break;
25828c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS:
25838c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS:
25848c2ecf20Sopenharmony_ci			pvt->pci_ras = pdev;
25858c2ecf20Sopenharmony_ci			break;
25868c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0:
25878c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1:
25888c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2:
25898c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3:
25908c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0:
25918c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1:
25928c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD2:
25938c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD3:
25948c2ecf20Sopenharmony_ci		{
25958c2ecf20Sopenharmony_ci			int id = TAD_DEV_TO_CHAN(pdev->device);
25968c2ecf20Sopenharmony_ci			pvt->pci_tad[id] = pdev;
25978c2ecf20Sopenharmony_ci			saw_chan_mask |= 1 << id;
25988c2ecf20Sopenharmony_ci		}
25998c2ecf20Sopenharmony_ci			break;
26008c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0:
26018c2ecf20Sopenharmony_ci			pvt->pci_ddrio = pdev;
26028c2ecf20Sopenharmony_ci			break;
26038c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0:
26048c2ecf20Sopenharmony_ci			pvt->pci_ddrio = pdev;
26058c2ecf20Sopenharmony_ci			break;
26068c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_IBRIDGE_SAD:
26078c2ecf20Sopenharmony_ci			pvt->pci_sad0 = pdev;
26088c2ecf20Sopenharmony_ci			break;
26098c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_IBRIDGE_BR0:
26108c2ecf20Sopenharmony_ci			pvt->pci_br0 = pdev;
26118c2ecf20Sopenharmony_ci			break;
26128c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_IBRIDGE_BR1:
26138c2ecf20Sopenharmony_ci			pvt->pci_br1 = pdev;
26148c2ecf20Sopenharmony_ci			break;
26158c2ecf20Sopenharmony_ci		default:
26168c2ecf20Sopenharmony_ci			goto error;
26178c2ecf20Sopenharmony_ci		}
26188c2ecf20Sopenharmony_ci
26198c2ecf20Sopenharmony_ci		edac_dbg(0, "Associated PCI %02x.%02d.%d with dev = %p\n",
26208c2ecf20Sopenharmony_ci			 sbridge_dev->bus,
26218c2ecf20Sopenharmony_ci			 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
26228c2ecf20Sopenharmony_ci			 pdev);
26238c2ecf20Sopenharmony_ci	}
26248c2ecf20Sopenharmony_ci
26258c2ecf20Sopenharmony_ci	/* Check if everything were registered */
26268c2ecf20Sopenharmony_ci	if (!pvt->pci_sad0 || !pvt->pci_ha || !pvt->pci_br0 ||
26278c2ecf20Sopenharmony_ci	    !pvt->pci_br1 || !pvt->pci_ras || !pvt->pci_ta)
26288c2ecf20Sopenharmony_ci		goto enodev;
26298c2ecf20Sopenharmony_ci
26308c2ecf20Sopenharmony_ci	if (saw_chan_mask != 0x0f && /* -EN/-EX */
26318c2ecf20Sopenharmony_ci	    saw_chan_mask != 0x03)   /* -EP */
26328c2ecf20Sopenharmony_ci		goto enodev;
26338c2ecf20Sopenharmony_ci	return 0;
26348c2ecf20Sopenharmony_ci
26358c2ecf20Sopenharmony_cienodev:
26368c2ecf20Sopenharmony_ci	sbridge_printk(KERN_ERR, "Some needed devices are missing\n");
26378c2ecf20Sopenharmony_ci	return -ENODEV;
26388c2ecf20Sopenharmony_ci
26398c2ecf20Sopenharmony_cierror:
26408c2ecf20Sopenharmony_ci	sbridge_printk(KERN_ERR,
26418c2ecf20Sopenharmony_ci		       "Unexpected device %02x:%02x\n", PCI_VENDOR_ID_INTEL,
26428c2ecf20Sopenharmony_ci			pdev->device);
26438c2ecf20Sopenharmony_ci	return -EINVAL;
26448c2ecf20Sopenharmony_ci}
26458c2ecf20Sopenharmony_ci
26468c2ecf20Sopenharmony_cistatic int haswell_mci_bind_devs(struct mem_ctl_info *mci,
26478c2ecf20Sopenharmony_ci				 struct sbridge_dev *sbridge_dev)
26488c2ecf20Sopenharmony_ci{
26498c2ecf20Sopenharmony_ci	struct sbridge_pvt *pvt = mci->pvt_info;
26508c2ecf20Sopenharmony_ci	struct pci_dev *pdev;
26518c2ecf20Sopenharmony_ci	u8 saw_chan_mask = 0;
26528c2ecf20Sopenharmony_ci	int i;
26538c2ecf20Sopenharmony_ci
26548c2ecf20Sopenharmony_ci	/* there's only one device per system; not tied to any bus */
26558c2ecf20Sopenharmony_ci	if (pvt->info.pci_vtd == NULL)
26568c2ecf20Sopenharmony_ci		/* result will be checked later */
26578c2ecf20Sopenharmony_ci		pvt->info.pci_vtd = pci_get_device(PCI_VENDOR_ID_INTEL,
26588c2ecf20Sopenharmony_ci						   PCI_DEVICE_ID_INTEL_HASWELL_IMC_VTD_MISC,
26598c2ecf20Sopenharmony_ci						   NULL);
26608c2ecf20Sopenharmony_ci
26618c2ecf20Sopenharmony_ci	for (i = 0; i < sbridge_dev->n_devs; i++) {
26628c2ecf20Sopenharmony_ci		pdev = sbridge_dev->pdev[i];
26638c2ecf20Sopenharmony_ci		if (!pdev)
26648c2ecf20Sopenharmony_ci			continue;
26658c2ecf20Sopenharmony_ci
26668c2ecf20Sopenharmony_ci		switch (pdev->device) {
26678c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD0:
26688c2ecf20Sopenharmony_ci			pvt->pci_sad0 = pdev;
26698c2ecf20Sopenharmony_ci			break;
26708c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD1:
26718c2ecf20Sopenharmony_ci			pvt->pci_sad1 = pdev;
26728c2ecf20Sopenharmony_ci			break;
26738c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0:
26748c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1:
26758c2ecf20Sopenharmony_ci			pvt->pci_ha = pdev;
26768c2ecf20Sopenharmony_ci			break;
26778c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA:
26788c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA:
26798c2ecf20Sopenharmony_ci			pvt->pci_ta = pdev;
26808c2ecf20Sopenharmony_ci			break;
26818c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TM:
26828c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TM:
26838c2ecf20Sopenharmony_ci			pvt->pci_ras = pdev;
26848c2ecf20Sopenharmony_ci			break;
26858c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD0:
26868c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD1:
26878c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD2:
26888c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3:
26898c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD0:
26908c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD1:
26918c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD2:
26928c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD3:
26938c2ecf20Sopenharmony_ci		{
26948c2ecf20Sopenharmony_ci			int id = TAD_DEV_TO_CHAN(pdev->device);
26958c2ecf20Sopenharmony_ci			pvt->pci_tad[id] = pdev;
26968c2ecf20Sopenharmony_ci			saw_chan_mask |= 1 << id;
26978c2ecf20Sopenharmony_ci		}
26988c2ecf20Sopenharmony_ci			break;
26998c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0:
27008c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO1:
27018c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO2:
27028c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO3:
27038c2ecf20Sopenharmony_ci			if (!pvt->pci_ddrio)
27048c2ecf20Sopenharmony_ci				pvt->pci_ddrio = pdev;
27058c2ecf20Sopenharmony_ci			break;
27068c2ecf20Sopenharmony_ci		default:
27078c2ecf20Sopenharmony_ci			break;
27088c2ecf20Sopenharmony_ci		}
27098c2ecf20Sopenharmony_ci
27108c2ecf20Sopenharmony_ci		edac_dbg(0, "Associated PCI %02x.%02d.%d with dev = %p\n",
27118c2ecf20Sopenharmony_ci			 sbridge_dev->bus,
27128c2ecf20Sopenharmony_ci			 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
27138c2ecf20Sopenharmony_ci			 pdev);
27148c2ecf20Sopenharmony_ci	}
27158c2ecf20Sopenharmony_ci
27168c2ecf20Sopenharmony_ci	/* Check if everything were registered */
27178c2ecf20Sopenharmony_ci	if (!pvt->pci_sad0 || !pvt->pci_ha || !pvt->pci_sad1 ||
27188c2ecf20Sopenharmony_ci	    !pvt->pci_ras  || !pvt->pci_ta || !pvt->info.pci_vtd)
27198c2ecf20Sopenharmony_ci		goto enodev;
27208c2ecf20Sopenharmony_ci
27218c2ecf20Sopenharmony_ci	if (saw_chan_mask != 0x0f && /* -EN/-EX */
27228c2ecf20Sopenharmony_ci	    saw_chan_mask != 0x03)   /* -EP */
27238c2ecf20Sopenharmony_ci		goto enodev;
27248c2ecf20Sopenharmony_ci	return 0;
27258c2ecf20Sopenharmony_ci
27268c2ecf20Sopenharmony_cienodev:
27278c2ecf20Sopenharmony_ci	sbridge_printk(KERN_ERR, "Some needed devices are missing\n");
27288c2ecf20Sopenharmony_ci	return -ENODEV;
27298c2ecf20Sopenharmony_ci}
27308c2ecf20Sopenharmony_ci
27318c2ecf20Sopenharmony_cistatic int broadwell_mci_bind_devs(struct mem_ctl_info *mci,
27328c2ecf20Sopenharmony_ci				 struct sbridge_dev *sbridge_dev)
27338c2ecf20Sopenharmony_ci{
27348c2ecf20Sopenharmony_ci	struct sbridge_pvt *pvt = mci->pvt_info;
27358c2ecf20Sopenharmony_ci	struct pci_dev *pdev;
27368c2ecf20Sopenharmony_ci	u8 saw_chan_mask = 0;
27378c2ecf20Sopenharmony_ci	int i;
27388c2ecf20Sopenharmony_ci
27398c2ecf20Sopenharmony_ci	/* there's only one device per system; not tied to any bus */
27408c2ecf20Sopenharmony_ci	if (pvt->info.pci_vtd == NULL)
27418c2ecf20Sopenharmony_ci		/* result will be checked later */
27428c2ecf20Sopenharmony_ci		pvt->info.pci_vtd = pci_get_device(PCI_VENDOR_ID_INTEL,
27438c2ecf20Sopenharmony_ci						   PCI_DEVICE_ID_INTEL_BROADWELL_IMC_VTD_MISC,
27448c2ecf20Sopenharmony_ci						   NULL);
27458c2ecf20Sopenharmony_ci
27468c2ecf20Sopenharmony_ci	for (i = 0; i < sbridge_dev->n_devs; i++) {
27478c2ecf20Sopenharmony_ci		pdev = sbridge_dev->pdev[i];
27488c2ecf20Sopenharmony_ci		if (!pdev)
27498c2ecf20Sopenharmony_ci			continue;
27508c2ecf20Sopenharmony_ci
27518c2ecf20Sopenharmony_ci		switch (pdev->device) {
27528c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD0:
27538c2ecf20Sopenharmony_ci			pvt->pci_sad0 = pdev;
27548c2ecf20Sopenharmony_ci			break;
27558c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD1:
27568c2ecf20Sopenharmony_ci			pvt->pci_sad1 = pdev;
27578c2ecf20Sopenharmony_ci			break;
27588c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0:
27598c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1:
27608c2ecf20Sopenharmony_ci			pvt->pci_ha = pdev;
27618c2ecf20Sopenharmony_ci			break;
27628c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA:
27638c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TA:
27648c2ecf20Sopenharmony_ci			pvt->pci_ta = pdev;
27658c2ecf20Sopenharmony_ci			break;
27668c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TM:
27678c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TM:
27688c2ecf20Sopenharmony_ci			pvt->pci_ras = pdev;
27698c2ecf20Sopenharmony_ci			break;
27708c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD0:
27718c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD1:
27728c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD2:
27738c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD3:
27748c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD0:
27758c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD1:
27768c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD2:
27778c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA1_TAD3:
27788c2ecf20Sopenharmony_ci		{
27798c2ecf20Sopenharmony_ci			int id = TAD_DEV_TO_CHAN(pdev->device);
27808c2ecf20Sopenharmony_ci			pvt->pci_tad[id] = pdev;
27818c2ecf20Sopenharmony_ci			saw_chan_mask |= 1 << id;
27828c2ecf20Sopenharmony_ci		}
27838c2ecf20Sopenharmony_ci			break;
27848c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_DDRIO0:
27858c2ecf20Sopenharmony_ci			pvt->pci_ddrio = pdev;
27868c2ecf20Sopenharmony_ci			break;
27878c2ecf20Sopenharmony_ci		default:
27888c2ecf20Sopenharmony_ci			break;
27898c2ecf20Sopenharmony_ci		}
27908c2ecf20Sopenharmony_ci
27918c2ecf20Sopenharmony_ci		edac_dbg(0, "Associated PCI %02x.%02d.%d with dev = %p\n",
27928c2ecf20Sopenharmony_ci			 sbridge_dev->bus,
27938c2ecf20Sopenharmony_ci			 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
27948c2ecf20Sopenharmony_ci			 pdev);
27958c2ecf20Sopenharmony_ci	}
27968c2ecf20Sopenharmony_ci
27978c2ecf20Sopenharmony_ci	/* Check if everything were registered */
27988c2ecf20Sopenharmony_ci	if (!pvt->pci_sad0 || !pvt->pci_ha || !pvt->pci_sad1 ||
27998c2ecf20Sopenharmony_ci	    !pvt->pci_ras  || !pvt->pci_ta || !pvt->info.pci_vtd)
28008c2ecf20Sopenharmony_ci		goto enodev;
28018c2ecf20Sopenharmony_ci
28028c2ecf20Sopenharmony_ci	if (saw_chan_mask != 0x0f && /* -EN/-EX */
28038c2ecf20Sopenharmony_ci	    saw_chan_mask != 0x03)   /* -EP */
28048c2ecf20Sopenharmony_ci		goto enodev;
28058c2ecf20Sopenharmony_ci	return 0;
28068c2ecf20Sopenharmony_ci
28078c2ecf20Sopenharmony_cienodev:
28088c2ecf20Sopenharmony_ci	sbridge_printk(KERN_ERR, "Some needed devices are missing\n");
28098c2ecf20Sopenharmony_ci	return -ENODEV;
28108c2ecf20Sopenharmony_ci}
28118c2ecf20Sopenharmony_ci
28128c2ecf20Sopenharmony_cistatic int knl_mci_bind_devs(struct mem_ctl_info *mci,
28138c2ecf20Sopenharmony_ci			struct sbridge_dev *sbridge_dev)
28148c2ecf20Sopenharmony_ci{
28158c2ecf20Sopenharmony_ci	struct sbridge_pvt *pvt = mci->pvt_info;
28168c2ecf20Sopenharmony_ci	struct pci_dev *pdev;
28178c2ecf20Sopenharmony_ci	int dev, func;
28188c2ecf20Sopenharmony_ci
28198c2ecf20Sopenharmony_ci	int i;
28208c2ecf20Sopenharmony_ci	int devidx;
28218c2ecf20Sopenharmony_ci
28228c2ecf20Sopenharmony_ci	for (i = 0; i < sbridge_dev->n_devs; i++) {
28238c2ecf20Sopenharmony_ci		pdev = sbridge_dev->pdev[i];
28248c2ecf20Sopenharmony_ci		if (!pdev)
28258c2ecf20Sopenharmony_ci			continue;
28268c2ecf20Sopenharmony_ci
28278c2ecf20Sopenharmony_ci		/* Extract PCI device and function. */
28288c2ecf20Sopenharmony_ci		dev = (pdev->devfn >> 3) & 0x1f;
28298c2ecf20Sopenharmony_ci		func = pdev->devfn & 0x7;
28308c2ecf20Sopenharmony_ci
28318c2ecf20Sopenharmony_ci		switch (pdev->device) {
28328c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_KNL_IMC_MC:
28338c2ecf20Sopenharmony_ci			if (dev == 8)
28348c2ecf20Sopenharmony_ci				pvt->knl.pci_mc0 = pdev;
28358c2ecf20Sopenharmony_ci			else if (dev == 9)
28368c2ecf20Sopenharmony_ci				pvt->knl.pci_mc1 = pdev;
28378c2ecf20Sopenharmony_ci			else {
28388c2ecf20Sopenharmony_ci				sbridge_printk(KERN_ERR,
28398c2ecf20Sopenharmony_ci					"Memory controller in unexpected place! (dev %d, fn %d)\n",
28408c2ecf20Sopenharmony_ci					dev, func);
28418c2ecf20Sopenharmony_ci				continue;
28428c2ecf20Sopenharmony_ci			}
28438c2ecf20Sopenharmony_ci			break;
28448c2ecf20Sopenharmony_ci
28458c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0:
28468c2ecf20Sopenharmony_ci			pvt->pci_sad0 = pdev;
28478c2ecf20Sopenharmony_ci			break;
28488c2ecf20Sopenharmony_ci
28498c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_KNL_IMC_SAD1:
28508c2ecf20Sopenharmony_ci			pvt->pci_sad1 = pdev;
28518c2ecf20Sopenharmony_ci			break;
28528c2ecf20Sopenharmony_ci
28538c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_KNL_IMC_CHA:
28548c2ecf20Sopenharmony_ci			/* There are one of these per tile, and range from
28558c2ecf20Sopenharmony_ci			 * 1.14.0 to 1.18.5.
28568c2ecf20Sopenharmony_ci			 */
28578c2ecf20Sopenharmony_ci			devidx = ((dev-14)*8)+func;
28588c2ecf20Sopenharmony_ci
28598c2ecf20Sopenharmony_ci			if (devidx < 0 || devidx >= KNL_MAX_CHAS) {
28608c2ecf20Sopenharmony_ci				sbridge_printk(KERN_ERR,
28618c2ecf20Sopenharmony_ci					"Caching and Home Agent in unexpected place! (dev %d, fn %d)\n",
28628c2ecf20Sopenharmony_ci					dev, func);
28638c2ecf20Sopenharmony_ci				continue;
28648c2ecf20Sopenharmony_ci			}
28658c2ecf20Sopenharmony_ci
28668c2ecf20Sopenharmony_ci			WARN_ON(pvt->knl.pci_cha[devidx] != NULL);
28678c2ecf20Sopenharmony_ci
28688c2ecf20Sopenharmony_ci			pvt->knl.pci_cha[devidx] = pdev;
28698c2ecf20Sopenharmony_ci			break;
28708c2ecf20Sopenharmony_ci
28718c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_KNL_IMC_CHAN:
28728c2ecf20Sopenharmony_ci			devidx = -1;
28738c2ecf20Sopenharmony_ci
28748c2ecf20Sopenharmony_ci			/*
28758c2ecf20Sopenharmony_ci			 *  MC0 channels 0-2 are device 9 function 2-4,
28768c2ecf20Sopenharmony_ci			 *  MC1 channels 3-5 are device 8 function 2-4.
28778c2ecf20Sopenharmony_ci			 */
28788c2ecf20Sopenharmony_ci
28798c2ecf20Sopenharmony_ci			if (dev == 9)
28808c2ecf20Sopenharmony_ci				devidx = func-2;
28818c2ecf20Sopenharmony_ci			else if (dev == 8)
28828c2ecf20Sopenharmony_ci				devidx = 3 + (func-2);
28838c2ecf20Sopenharmony_ci
28848c2ecf20Sopenharmony_ci			if (devidx < 0 || devidx >= KNL_MAX_CHANNELS) {
28858c2ecf20Sopenharmony_ci				sbridge_printk(KERN_ERR,
28868c2ecf20Sopenharmony_ci					"DRAM Channel Registers in unexpected place! (dev %d, fn %d)\n",
28878c2ecf20Sopenharmony_ci					dev, func);
28888c2ecf20Sopenharmony_ci				continue;
28898c2ecf20Sopenharmony_ci			}
28908c2ecf20Sopenharmony_ci
28918c2ecf20Sopenharmony_ci			WARN_ON(pvt->knl.pci_channel[devidx] != NULL);
28928c2ecf20Sopenharmony_ci			pvt->knl.pci_channel[devidx] = pdev;
28938c2ecf20Sopenharmony_ci			break;
28948c2ecf20Sopenharmony_ci
28958c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_KNL_IMC_TOLHM:
28968c2ecf20Sopenharmony_ci			pvt->knl.pci_mc_info = pdev;
28978c2ecf20Sopenharmony_ci			break;
28988c2ecf20Sopenharmony_ci
28998c2ecf20Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_KNL_IMC_TA:
29008c2ecf20Sopenharmony_ci			pvt->pci_ta = pdev;
29018c2ecf20Sopenharmony_ci			break;
29028c2ecf20Sopenharmony_ci
29038c2ecf20Sopenharmony_ci		default:
29048c2ecf20Sopenharmony_ci			sbridge_printk(KERN_ERR, "Unexpected device %d\n",
29058c2ecf20Sopenharmony_ci				pdev->device);
29068c2ecf20Sopenharmony_ci			break;
29078c2ecf20Sopenharmony_ci		}
29088c2ecf20Sopenharmony_ci	}
29098c2ecf20Sopenharmony_ci
29108c2ecf20Sopenharmony_ci	if (!pvt->knl.pci_mc0  || !pvt->knl.pci_mc1 ||
29118c2ecf20Sopenharmony_ci	    !pvt->pci_sad0     || !pvt->pci_sad1    ||
29128c2ecf20Sopenharmony_ci	    !pvt->pci_ta) {
29138c2ecf20Sopenharmony_ci		goto enodev;
29148c2ecf20Sopenharmony_ci	}
29158c2ecf20Sopenharmony_ci
29168c2ecf20Sopenharmony_ci	for (i = 0; i < KNL_MAX_CHANNELS; i++) {
29178c2ecf20Sopenharmony_ci		if (!pvt->knl.pci_channel[i]) {
29188c2ecf20Sopenharmony_ci			sbridge_printk(KERN_ERR, "Missing channel %d\n", i);
29198c2ecf20Sopenharmony_ci			goto enodev;
29208c2ecf20Sopenharmony_ci		}
29218c2ecf20Sopenharmony_ci	}
29228c2ecf20Sopenharmony_ci
29238c2ecf20Sopenharmony_ci	for (i = 0; i < KNL_MAX_CHAS; i++) {
29248c2ecf20Sopenharmony_ci		if (!pvt->knl.pci_cha[i]) {
29258c2ecf20Sopenharmony_ci			sbridge_printk(KERN_ERR, "Missing CHA %d\n", i);
29268c2ecf20Sopenharmony_ci			goto enodev;
29278c2ecf20Sopenharmony_ci		}
29288c2ecf20Sopenharmony_ci	}
29298c2ecf20Sopenharmony_ci
29308c2ecf20Sopenharmony_ci	return 0;
29318c2ecf20Sopenharmony_ci
29328c2ecf20Sopenharmony_cienodev:
29338c2ecf20Sopenharmony_ci	sbridge_printk(KERN_ERR, "Some needed devices are missing\n");
29348c2ecf20Sopenharmony_ci	return -ENODEV;
29358c2ecf20Sopenharmony_ci}
29368c2ecf20Sopenharmony_ci
29378c2ecf20Sopenharmony_ci/****************************************************************************
29388c2ecf20Sopenharmony_ci			Error check routines
29398c2ecf20Sopenharmony_ci ****************************************************************************/
29408c2ecf20Sopenharmony_ci
29418c2ecf20Sopenharmony_ci/*
29428c2ecf20Sopenharmony_ci * While Sandy Bridge has error count registers, SMI BIOS read values from
29438c2ecf20Sopenharmony_ci * and resets the counters. So, they are not reliable for the OS to read
29448c2ecf20Sopenharmony_ci * from them. So, we have no option but to just trust on whatever MCE is
29458c2ecf20Sopenharmony_ci * telling us about the errors.
29468c2ecf20Sopenharmony_ci */
29478c2ecf20Sopenharmony_cistatic void sbridge_mce_output_error(struct mem_ctl_info *mci,
29488c2ecf20Sopenharmony_ci				    const struct mce *m)
29498c2ecf20Sopenharmony_ci{
29508c2ecf20Sopenharmony_ci	struct mem_ctl_info *new_mci;
29518c2ecf20Sopenharmony_ci	struct sbridge_pvt *pvt = mci->pvt_info;
29528c2ecf20Sopenharmony_ci	enum hw_event_mc_err_type tp_event;
29538c2ecf20Sopenharmony_ci	char *optype, msg[256];
29548c2ecf20Sopenharmony_ci	bool ripv = GET_BITFIELD(m->mcgstatus, 0, 0);
29558c2ecf20Sopenharmony_ci	bool overflow = GET_BITFIELD(m->status, 62, 62);
29568c2ecf20Sopenharmony_ci	bool uncorrected_error = GET_BITFIELD(m->status, 61, 61);
29578c2ecf20Sopenharmony_ci	bool recoverable;
29588c2ecf20Sopenharmony_ci	u32 core_err_cnt = GET_BITFIELD(m->status, 38, 52);
29598c2ecf20Sopenharmony_ci	u32 mscod = GET_BITFIELD(m->status, 16, 31);
29608c2ecf20Sopenharmony_ci	u32 errcode = GET_BITFIELD(m->status, 0, 15);
29618c2ecf20Sopenharmony_ci	u32 channel = GET_BITFIELD(m->status, 0, 3);
29628c2ecf20Sopenharmony_ci	u32 optypenum = GET_BITFIELD(m->status, 4, 6);
29638c2ecf20Sopenharmony_ci	/*
29648c2ecf20Sopenharmony_ci	 * Bits 5-0 of MCi_MISC give the least significant bit that is valid.
29658c2ecf20Sopenharmony_ci	 * A value 6 is for cache line aligned address, a value 12 is for page
29668c2ecf20Sopenharmony_ci	 * aligned address reported by patrol scrubber.
29678c2ecf20Sopenharmony_ci	 */
29688c2ecf20Sopenharmony_ci	u32 lsb = GET_BITFIELD(m->misc, 0, 5);
29698c2ecf20Sopenharmony_ci	long channel_mask, first_channel;
29708c2ecf20Sopenharmony_ci	u8  rank = 0xff, socket, ha;
29718c2ecf20Sopenharmony_ci	int rc, dimm;
29728c2ecf20Sopenharmony_ci	char *area_type = "DRAM";
29738c2ecf20Sopenharmony_ci
29748c2ecf20Sopenharmony_ci	if (pvt->info.type != SANDY_BRIDGE)
29758c2ecf20Sopenharmony_ci		recoverable = true;
29768c2ecf20Sopenharmony_ci	else
29778c2ecf20Sopenharmony_ci		recoverable = GET_BITFIELD(m->status, 56, 56);
29788c2ecf20Sopenharmony_ci
29798c2ecf20Sopenharmony_ci	if (uncorrected_error) {
29808c2ecf20Sopenharmony_ci		core_err_cnt = 1;
29818c2ecf20Sopenharmony_ci		if (ripv) {
29828c2ecf20Sopenharmony_ci			tp_event = HW_EVENT_ERR_UNCORRECTED;
29838c2ecf20Sopenharmony_ci		} else {
29848c2ecf20Sopenharmony_ci			tp_event = HW_EVENT_ERR_FATAL;
29858c2ecf20Sopenharmony_ci		}
29868c2ecf20Sopenharmony_ci	} else {
29878c2ecf20Sopenharmony_ci		tp_event = HW_EVENT_ERR_CORRECTED;
29888c2ecf20Sopenharmony_ci	}
29898c2ecf20Sopenharmony_ci
29908c2ecf20Sopenharmony_ci	/*
29918c2ecf20Sopenharmony_ci	 * According with Table 15-9 of the Intel Architecture spec vol 3A,
29928c2ecf20Sopenharmony_ci	 * memory errors should fit in this mask:
29938c2ecf20Sopenharmony_ci	 *	000f 0000 1mmm cccc (binary)
29948c2ecf20Sopenharmony_ci	 * where:
29958c2ecf20Sopenharmony_ci	 *	f = Correction Report Filtering Bit. If 1, subsequent errors
29968c2ecf20Sopenharmony_ci	 *	    won't be shown
29978c2ecf20Sopenharmony_ci	 *	mmm = error type
29988c2ecf20Sopenharmony_ci	 *	cccc = channel
29998c2ecf20Sopenharmony_ci	 * If the mask doesn't match, report an error to the parsing logic
30008c2ecf20Sopenharmony_ci	 */
30018c2ecf20Sopenharmony_ci	switch (optypenum) {
30028c2ecf20Sopenharmony_ci	case 0:
30038c2ecf20Sopenharmony_ci		optype = "generic undef request error";
30048c2ecf20Sopenharmony_ci		break;
30058c2ecf20Sopenharmony_ci	case 1:
30068c2ecf20Sopenharmony_ci		optype = "memory read error";
30078c2ecf20Sopenharmony_ci		break;
30088c2ecf20Sopenharmony_ci	case 2:
30098c2ecf20Sopenharmony_ci		optype = "memory write error";
30108c2ecf20Sopenharmony_ci		break;
30118c2ecf20Sopenharmony_ci	case 3:
30128c2ecf20Sopenharmony_ci		optype = "addr/cmd error";
30138c2ecf20Sopenharmony_ci		break;
30148c2ecf20Sopenharmony_ci	case 4:
30158c2ecf20Sopenharmony_ci		optype = "memory scrubbing error";
30168c2ecf20Sopenharmony_ci		break;
30178c2ecf20Sopenharmony_ci	default:
30188c2ecf20Sopenharmony_ci		optype = "reserved";
30198c2ecf20Sopenharmony_ci		break;
30208c2ecf20Sopenharmony_ci	}
30218c2ecf20Sopenharmony_ci
30228c2ecf20Sopenharmony_ci	if (pvt->info.type == KNIGHTS_LANDING) {
30238c2ecf20Sopenharmony_ci		if (channel == 14) {
30248c2ecf20Sopenharmony_ci			edac_dbg(0, "%s%s err_code:%04x:%04x EDRAM bank %d\n",
30258c2ecf20Sopenharmony_ci				overflow ? " OVERFLOW" : "",
30268c2ecf20Sopenharmony_ci				(uncorrected_error && recoverable)
30278c2ecf20Sopenharmony_ci				? " recoverable" : "",
30288c2ecf20Sopenharmony_ci				mscod, errcode,
30298c2ecf20Sopenharmony_ci				m->bank);
30308c2ecf20Sopenharmony_ci		} else {
30318c2ecf20Sopenharmony_ci			char A = *("A");
30328c2ecf20Sopenharmony_ci
30338c2ecf20Sopenharmony_ci			/*
30348c2ecf20Sopenharmony_ci			 * Reported channel is in range 0-2, so we can't map it
30358c2ecf20Sopenharmony_ci			 * back to mc. To figure out mc we check machine check
30368c2ecf20Sopenharmony_ci			 * bank register that reported this error.
30378c2ecf20Sopenharmony_ci			 * bank15 means mc0 and bank16 means mc1.
30388c2ecf20Sopenharmony_ci			 */
30398c2ecf20Sopenharmony_ci			channel = knl_channel_remap(m->bank == 16, channel);
30408c2ecf20Sopenharmony_ci			channel_mask = 1 << channel;
30418c2ecf20Sopenharmony_ci
30428c2ecf20Sopenharmony_ci			snprintf(msg, sizeof(msg),
30438c2ecf20Sopenharmony_ci				"%s%s err_code:%04x:%04x channel:%d (DIMM_%c)",
30448c2ecf20Sopenharmony_ci				overflow ? " OVERFLOW" : "",
30458c2ecf20Sopenharmony_ci				(uncorrected_error && recoverable)
30468c2ecf20Sopenharmony_ci				? " recoverable" : " ",
30478c2ecf20Sopenharmony_ci				mscod, errcode, channel, A + channel);
30488c2ecf20Sopenharmony_ci			edac_mc_handle_error(tp_event, mci, core_err_cnt,
30498c2ecf20Sopenharmony_ci				m->addr >> PAGE_SHIFT, m->addr & ~PAGE_MASK, 0,
30508c2ecf20Sopenharmony_ci				channel, 0, -1,
30518c2ecf20Sopenharmony_ci				optype, msg);
30528c2ecf20Sopenharmony_ci		}
30538c2ecf20Sopenharmony_ci		return;
30548c2ecf20Sopenharmony_ci	} else if (lsb < 12) {
30558c2ecf20Sopenharmony_ci		rc = get_memory_error_data(mci, m->addr, &socket, &ha,
30568c2ecf20Sopenharmony_ci					   &channel_mask, &rank,
30578c2ecf20Sopenharmony_ci					   &area_type, msg);
30588c2ecf20Sopenharmony_ci	} else {
30598c2ecf20Sopenharmony_ci		rc = get_memory_error_data_from_mce(mci, m, &socket, &ha,
30608c2ecf20Sopenharmony_ci						    &channel_mask, msg);
30618c2ecf20Sopenharmony_ci	}
30628c2ecf20Sopenharmony_ci
30638c2ecf20Sopenharmony_ci	if (rc < 0)
30648c2ecf20Sopenharmony_ci		goto err_parsing;
30658c2ecf20Sopenharmony_ci	new_mci = get_mci_for_node_id(socket, ha);
30668c2ecf20Sopenharmony_ci	if (!new_mci) {
30678c2ecf20Sopenharmony_ci		strcpy(msg, "Error: socket got corrupted!");
30688c2ecf20Sopenharmony_ci		goto err_parsing;
30698c2ecf20Sopenharmony_ci	}
30708c2ecf20Sopenharmony_ci	mci = new_mci;
30718c2ecf20Sopenharmony_ci	pvt = mci->pvt_info;
30728c2ecf20Sopenharmony_ci
30738c2ecf20Sopenharmony_ci	first_channel = find_first_bit(&channel_mask, NUM_CHANNELS);
30748c2ecf20Sopenharmony_ci
30758c2ecf20Sopenharmony_ci	if (rank == 0xff)
30768c2ecf20Sopenharmony_ci		dimm = -1;
30778c2ecf20Sopenharmony_ci	else if (rank < 4)
30788c2ecf20Sopenharmony_ci		dimm = 0;
30798c2ecf20Sopenharmony_ci	else if (rank < 8)
30808c2ecf20Sopenharmony_ci		dimm = 1;
30818c2ecf20Sopenharmony_ci	else
30828c2ecf20Sopenharmony_ci		dimm = 2;
30838c2ecf20Sopenharmony_ci
30848c2ecf20Sopenharmony_ci	/*
30858c2ecf20Sopenharmony_ci	 * FIXME: On some memory configurations (mirror, lockstep), the
30868c2ecf20Sopenharmony_ci	 * Memory Controller can't point the error to a single DIMM. The
30878c2ecf20Sopenharmony_ci	 * EDAC core should be handling the channel mask, in order to point
30888c2ecf20Sopenharmony_ci	 * to the group of dimm's where the error may be happening.
30898c2ecf20Sopenharmony_ci	 */
30908c2ecf20Sopenharmony_ci	if (!pvt->is_lockstep && !pvt->is_cur_addr_mirrored && !pvt->is_close_pg)
30918c2ecf20Sopenharmony_ci		channel = first_channel;
30928c2ecf20Sopenharmony_ci
30938c2ecf20Sopenharmony_ci	snprintf(msg, sizeof(msg),
30948c2ecf20Sopenharmony_ci		 "%s%s area:%s err_code:%04x:%04x socket:%d ha:%d channel_mask:%ld rank:%d",
30958c2ecf20Sopenharmony_ci		 overflow ? " OVERFLOW" : "",
30968c2ecf20Sopenharmony_ci		 (uncorrected_error && recoverable) ? " recoverable" : "",
30978c2ecf20Sopenharmony_ci		 area_type,
30988c2ecf20Sopenharmony_ci		 mscod, errcode,
30998c2ecf20Sopenharmony_ci		 socket, ha,
31008c2ecf20Sopenharmony_ci		 channel_mask,
31018c2ecf20Sopenharmony_ci		 rank);
31028c2ecf20Sopenharmony_ci
31038c2ecf20Sopenharmony_ci	edac_dbg(0, "%s\n", msg);
31048c2ecf20Sopenharmony_ci
31058c2ecf20Sopenharmony_ci	/* FIXME: need support for channel mask */
31068c2ecf20Sopenharmony_ci
31078c2ecf20Sopenharmony_ci	if (channel == CHANNEL_UNSPECIFIED)
31088c2ecf20Sopenharmony_ci		channel = -1;
31098c2ecf20Sopenharmony_ci
31108c2ecf20Sopenharmony_ci	/* Call the helper to output message */
31118c2ecf20Sopenharmony_ci	edac_mc_handle_error(tp_event, mci, core_err_cnt,
31128c2ecf20Sopenharmony_ci			     m->addr >> PAGE_SHIFT, m->addr & ~PAGE_MASK, 0,
31138c2ecf20Sopenharmony_ci			     channel, dimm, -1,
31148c2ecf20Sopenharmony_ci			     optype, msg);
31158c2ecf20Sopenharmony_ci	return;
31168c2ecf20Sopenharmony_cierr_parsing:
31178c2ecf20Sopenharmony_ci	edac_mc_handle_error(tp_event, mci, core_err_cnt, 0, 0, 0,
31188c2ecf20Sopenharmony_ci			     -1, -1, -1,
31198c2ecf20Sopenharmony_ci			     msg, "");
31208c2ecf20Sopenharmony_ci
31218c2ecf20Sopenharmony_ci}
31228c2ecf20Sopenharmony_ci
31238c2ecf20Sopenharmony_ci/*
31248c2ecf20Sopenharmony_ci * Check that logging is enabled and that this is the right type
31258c2ecf20Sopenharmony_ci * of error for us to handle.
31268c2ecf20Sopenharmony_ci */
31278c2ecf20Sopenharmony_cistatic int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val,
31288c2ecf20Sopenharmony_ci				   void *data)
31298c2ecf20Sopenharmony_ci{
31308c2ecf20Sopenharmony_ci	struct mce *mce = (struct mce *)data;
31318c2ecf20Sopenharmony_ci	struct mem_ctl_info *mci;
31328c2ecf20Sopenharmony_ci	char *type;
31338c2ecf20Sopenharmony_ci
31348c2ecf20Sopenharmony_ci	if (mce->kflags & MCE_HANDLED_CEC)
31358c2ecf20Sopenharmony_ci		return NOTIFY_DONE;
31368c2ecf20Sopenharmony_ci
31378c2ecf20Sopenharmony_ci	/*
31388c2ecf20Sopenharmony_ci	 * Just let mcelog handle it if the error is
31398c2ecf20Sopenharmony_ci	 * outside the memory controller. A memory error
31408c2ecf20Sopenharmony_ci	 * is indicated by bit 7 = 1 and bits = 8-11,13-15 = 0.
31418c2ecf20Sopenharmony_ci	 * bit 12 has an special meaning.
31428c2ecf20Sopenharmony_ci	 */
31438c2ecf20Sopenharmony_ci	if ((mce->status & 0xefff) >> 7 != 1)
31448c2ecf20Sopenharmony_ci		return NOTIFY_DONE;
31458c2ecf20Sopenharmony_ci
31468c2ecf20Sopenharmony_ci	/* Check ADDRV bit in STATUS */
31478c2ecf20Sopenharmony_ci	if (!GET_BITFIELD(mce->status, 58, 58))
31488c2ecf20Sopenharmony_ci		return NOTIFY_DONE;
31498c2ecf20Sopenharmony_ci
31508c2ecf20Sopenharmony_ci	/* Check MISCV bit in STATUS */
31518c2ecf20Sopenharmony_ci	if (!GET_BITFIELD(mce->status, 59, 59))
31528c2ecf20Sopenharmony_ci		return NOTIFY_DONE;
31538c2ecf20Sopenharmony_ci
31548c2ecf20Sopenharmony_ci	/* Check address type in MISC (physical address only) */
31558c2ecf20Sopenharmony_ci	if (GET_BITFIELD(mce->misc, 6, 8) != 2)
31568c2ecf20Sopenharmony_ci		return NOTIFY_DONE;
31578c2ecf20Sopenharmony_ci
31588c2ecf20Sopenharmony_ci	mci = get_mci_for_node_id(mce->socketid, IMC0);
31598c2ecf20Sopenharmony_ci	if (!mci)
31608c2ecf20Sopenharmony_ci		return NOTIFY_DONE;
31618c2ecf20Sopenharmony_ci
31628c2ecf20Sopenharmony_ci	if (mce->mcgstatus & MCG_STATUS_MCIP)
31638c2ecf20Sopenharmony_ci		type = "Exception";
31648c2ecf20Sopenharmony_ci	else
31658c2ecf20Sopenharmony_ci		type = "Event";
31668c2ecf20Sopenharmony_ci
31678c2ecf20Sopenharmony_ci	sbridge_mc_printk(mci, KERN_DEBUG, "HANDLING MCE MEMORY ERROR\n");
31688c2ecf20Sopenharmony_ci
31698c2ecf20Sopenharmony_ci	sbridge_mc_printk(mci, KERN_DEBUG, "CPU %d: Machine Check %s: %Lx "
31708c2ecf20Sopenharmony_ci			  "Bank %d: %016Lx\n", mce->extcpu, type,
31718c2ecf20Sopenharmony_ci			  mce->mcgstatus, mce->bank, mce->status);
31728c2ecf20Sopenharmony_ci	sbridge_mc_printk(mci, KERN_DEBUG, "TSC %llx ", mce->tsc);
31738c2ecf20Sopenharmony_ci	sbridge_mc_printk(mci, KERN_DEBUG, "ADDR %llx ", mce->addr);
31748c2ecf20Sopenharmony_ci	sbridge_mc_printk(mci, KERN_DEBUG, "MISC %llx ", mce->misc);
31758c2ecf20Sopenharmony_ci
31768c2ecf20Sopenharmony_ci	sbridge_mc_printk(mci, KERN_DEBUG, "PROCESSOR %u:%x TIME %llu SOCKET "
31778c2ecf20Sopenharmony_ci			  "%u APIC %x\n", mce->cpuvendor, mce->cpuid,
31788c2ecf20Sopenharmony_ci			  mce->time, mce->socketid, mce->apicid);
31798c2ecf20Sopenharmony_ci
31808c2ecf20Sopenharmony_ci	sbridge_mce_output_error(mci, mce);
31818c2ecf20Sopenharmony_ci
31828c2ecf20Sopenharmony_ci	/* Advice mcelog that the error were handled */
31838c2ecf20Sopenharmony_ci	mce->kflags |= MCE_HANDLED_EDAC;
31848c2ecf20Sopenharmony_ci	return NOTIFY_OK;
31858c2ecf20Sopenharmony_ci}
31868c2ecf20Sopenharmony_ci
31878c2ecf20Sopenharmony_cistatic struct notifier_block sbridge_mce_dec = {
31888c2ecf20Sopenharmony_ci	.notifier_call	= sbridge_mce_check_error,
31898c2ecf20Sopenharmony_ci	.priority	= MCE_PRIO_EDAC,
31908c2ecf20Sopenharmony_ci};
31918c2ecf20Sopenharmony_ci
31928c2ecf20Sopenharmony_ci/****************************************************************************
31938c2ecf20Sopenharmony_ci			EDAC register/unregister logic
31948c2ecf20Sopenharmony_ci ****************************************************************************/
31958c2ecf20Sopenharmony_ci
31968c2ecf20Sopenharmony_cistatic void sbridge_unregister_mci(struct sbridge_dev *sbridge_dev)
31978c2ecf20Sopenharmony_ci{
31988c2ecf20Sopenharmony_ci	struct mem_ctl_info *mci = sbridge_dev->mci;
31998c2ecf20Sopenharmony_ci
32008c2ecf20Sopenharmony_ci	if (unlikely(!mci || !mci->pvt_info)) {
32018c2ecf20Sopenharmony_ci		edac_dbg(0, "MC: dev = %p\n", &sbridge_dev->pdev[0]->dev);
32028c2ecf20Sopenharmony_ci
32038c2ecf20Sopenharmony_ci		sbridge_printk(KERN_ERR, "Couldn't find mci handler\n");
32048c2ecf20Sopenharmony_ci		return;
32058c2ecf20Sopenharmony_ci	}
32068c2ecf20Sopenharmony_ci
32078c2ecf20Sopenharmony_ci	edac_dbg(0, "MC: mci = %p, dev = %p\n",
32088c2ecf20Sopenharmony_ci		 mci, &sbridge_dev->pdev[0]->dev);
32098c2ecf20Sopenharmony_ci
32108c2ecf20Sopenharmony_ci	/* Remove MC sysfs nodes */
32118c2ecf20Sopenharmony_ci	edac_mc_del_mc(mci->pdev);
32128c2ecf20Sopenharmony_ci
32138c2ecf20Sopenharmony_ci	edac_dbg(1, "%s: free mci struct\n", mci->ctl_name);
32148c2ecf20Sopenharmony_ci	kfree(mci->ctl_name);
32158c2ecf20Sopenharmony_ci	edac_mc_free(mci);
32168c2ecf20Sopenharmony_ci	sbridge_dev->mci = NULL;
32178c2ecf20Sopenharmony_ci}
32188c2ecf20Sopenharmony_ci
32198c2ecf20Sopenharmony_cistatic int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
32208c2ecf20Sopenharmony_ci{
32218c2ecf20Sopenharmony_ci	struct mem_ctl_info *mci;
32228c2ecf20Sopenharmony_ci	struct edac_mc_layer layers[2];
32238c2ecf20Sopenharmony_ci	struct sbridge_pvt *pvt;
32248c2ecf20Sopenharmony_ci	struct pci_dev *pdev = sbridge_dev->pdev[0];
32258c2ecf20Sopenharmony_ci	int rc;
32268c2ecf20Sopenharmony_ci
32278c2ecf20Sopenharmony_ci	/* allocate a new MC control structure */
32288c2ecf20Sopenharmony_ci	layers[0].type = EDAC_MC_LAYER_CHANNEL;
32298c2ecf20Sopenharmony_ci	layers[0].size = type == KNIGHTS_LANDING ?
32308c2ecf20Sopenharmony_ci		KNL_MAX_CHANNELS : NUM_CHANNELS;
32318c2ecf20Sopenharmony_ci	layers[0].is_virt_csrow = false;
32328c2ecf20Sopenharmony_ci	layers[1].type = EDAC_MC_LAYER_SLOT;
32338c2ecf20Sopenharmony_ci	layers[1].size = type == KNIGHTS_LANDING ? 1 : MAX_DIMMS;
32348c2ecf20Sopenharmony_ci	layers[1].is_virt_csrow = true;
32358c2ecf20Sopenharmony_ci	mci = edac_mc_alloc(sbridge_dev->mc, ARRAY_SIZE(layers), layers,
32368c2ecf20Sopenharmony_ci			    sizeof(*pvt));
32378c2ecf20Sopenharmony_ci
32388c2ecf20Sopenharmony_ci	if (unlikely(!mci))
32398c2ecf20Sopenharmony_ci		return -ENOMEM;
32408c2ecf20Sopenharmony_ci
32418c2ecf20Sopenharmony_ci	edac_dbg(0, "MC: mci = %p, dev = %p\n",
32428c2ecf20Sopenharmony_ci		 mci, &pdev->dev);
32438c2ecf20Sopenharmony_ci
32448c2ecf20Sopenharmony_ci	pvt = mci->pvt_info;
32458c2ecf20Sopenharmony_ci	memset(pvt, 0, sizeof(*pvt));
32468c2ecf20Sopenharmony_ci
32478c2ecf20Sopenharmony_ci	/* Associate sbridge_dev and mci for future usage */
32488c2ecf20Sopenharmony_ci	pvt->sbridge_dev = sbridge_dev;
32498c2ecf20Sopenharmony_ci	sbridge_dev->mci = mci;
32508c2ecf20Sopenharmony_ci
32518c2ecf20Sopenharmony_ci	mci->mtype_cap = type == KNIGHTS_LANDING ?
32528c2ecf20Sopenharmony_ci		MEM_FLAG_DDR4 : MEM_FLAG_DDR3;
32538c2ecf20Sopenharmony_ci	mci->edac_ctl_cap = EDAC_FLAG_NONE;
32548c2ecf20Sopenharmony_ci	mci->edac_cap = EDAC_FLAG_NONE;
32558c2ecf20Sopenharmony_ci	mci->mod_name = EDAC_MOD_STR;
32568c2ecf20Sopenharmony_ci	mci->dev_name = pci_name(pdev);
32578c2ecf20Sopenharmony_ci	mci->ctl_page_to_phys = NULL;
32588c2ecf20Sopenharmony_ci
32598c2ecf20Sopenharmony_ci	pvt->info.type = type;
32608c2ecf20Sopenharmony_ci	switch (type) {
32618c2ecf20Sopenharmony_ci	case IVY_BRIDGE:
32628c2ecf20Sopenharmony_ci		pvt->info.rankcfgr = IB_RANK_CFG_A;
32638c2ecf20Sopenharmony_ci		pvt->info.get_tolm = ibridge_get_tolm;
32648c2ecf20Sopenharmony_ci		pvt->info.get_tohm = ibridge_get_tohm;
32658c2ecf20Sopenharmony_ci		pvt->info.dram_rule = ibridge_dram_rule;
32668c2ecf20Sopenharmony_ci		pvt->info.get_memory_type = get_memory_type;
32678c2ecf20Sopenharmony_ci		pvt->info.get_node_id = get_node_id;
32688c2ecf20Sopenharmony_ci		pvt->info.get_ha = ibridge_get_ha;
32698c2ecf20Sopenharmony_ci		pvt->info.rir_limit = rir_limit;
32708c2ecf20Sopenharmony_ci		pvt->info.sad_limit = sad_limit;
32718c2ecf20Sopenharmony_ci		pvt->info.interleave_mode = interleave_mode;
32728c2ecf20Sopenharmony_ci		pvt->info.dram_attr = dram_attr;
32738c2ecf20Sopenharmony_ci		pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule);
32748c2ecf20Sopenharmony_ci		pvt->info.interleave_list = ibridge_interleave_list;
32758c2ecf20Sopenharmony_ci		pvt->info.interleave_pkg = ibridge_interleave_pkg;
32768c2ecf20Sopenharmony_ci		pvt->info.get_width = ibridge_get_width;
32778c2ecf20Sopenharmony_ci
32788c2ecf20Sopenharmony_ci		/* Store pci devices at mci for faster access */
32798c2ecf20Sopenharmony_ci		rc = ibridge_mci_bind_devs(mci, sbridge_dev);
32808c2ecf20Sopenharmony_ci		if (unlikely(rc < 0))
32818c2ecf20Sopenharmony_ci			goto fail0;
32828c2ecf20Sopenharmony_ci		get_source_id(mci);
32838c2ecf20Sopenharmony_ci		mci->ctl_name = kasprintf(GFP_KERNEL, "Ivy Bridge SrcID#%d_Ha#%d",
32848c2ecf20Sopenharmony_ci			pvt->sbridge_dev->source_id, pvt->sbridge_dev->dom);
32858c2ecf20Sopenharmony_ci		break;
32868c2ecf20Sopenharmony_ci	case SANDY_BRIDGE:
32878c2ecf20Sopenharmony_ci		pvt->info.rankcfgr = SB_RANK_CFG_A;
32888c2ecf20Sopenharmony_ci		pvt->info.get_tolm = sbridge_get_tolm;
32898c2ecf20Sopenharmony_ci		pvt->info.get_tohm = sbridge_get_tohm;
32908c2ecf20Sopenharmony_ci		pvt->info.dram_rule = sbridge_dram_rule;
32918c2ecf20Sopenharmony_ci		pvt->info.get_memory_type = get_memory_type;
32928c2ecf20Sopenharmony_ci		pvt->info.get_node_id = get_node_id;
32938c2ecf20Sopenharmony_ci		pvt->info.get_ha = sbridge_get_ha;
32948c2ecf20Sopenharmony_ci		pvt->info.rir_limit = rir_limit;
32958c2ecf20Sopenharmony_ci		pvt->info.sad_limit = sad_limit;
32968c2ecf20Sopenharmony_ci		pvt->info.interleave_mode = interleave_mode;
32978c2ecf20Sopenharmony_ci		pvt->info.dram_attr = dram_attr;
32988c2ecf20Sopenharmony_ci		pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule);
32998c2ecf20Sopenharmony_ci		pvt->info.interleave_list = sbridge_interleave_list;
33008c2ecf20Sopenharmony_ci		pvt->info.interleave_pkg = sbridge_interleave_pkg;
33018c2ecf20Sopenharmony_ci		pvt->info.get_width = sbridge_get_width;
33028c2ecf20Sopenharmony_ci
33038c2ecf20Sopenharmony_ci		/* Store pci devices at mci for faster access */
33048c2ecf20Sopenharmony_ci		rc = sbridge_mci_bind_devs(mci, sbridge_dev);
33058c2ecf20Sopenharmony_ci		if (unlikely(rc < 0))
33068c2ecf20Sopenharmony_ci			goto fail0;
33078c2ecf20Sopenharmony_ci		get_source_id(mci);
33088c2ecf20Sopenharmony_ci		mci->ctl_name = kasprintf(GFP_KERNEL, "Sandy Bridge SrcID#%d_Ha#%d",
33098c2ecf20Sopenharmony_ci			pvt->sbridge_dev->source_id, pvt->sbridge_dev->dom);
33108c2ecf20Sopenharmony_ci		break;
33118c2ecf20Sopenharmony_ci	case HASWELL:
33128c2ecf20Sopenharmony_ci		/* rankcfgr isn't used */
33138c2ecf20Sopenharmony_ci		pvt->info.get_tolm = haswell_get_tolm;
33148c2ecf20Sopenharmony_ci		pvt->info.get_tohm = haswell_get_tohm;
33158c2ecf20Sopenharmony_ci		pvt->info.dram_rule = ibridge_dram_rule;
33168c2ecf20Sopenharmony_ci		pvt->info.get_memory_type = haswell_get_memory_type;
33178c2ecf20Sopenharmony_ci		pvt->info.get_node_id = haswell_get_node_id;
33188c2ecf20Sopenharmony_ci		pvt->info.get_ha = ibridge_get_ha;
33198c2ecf20Sopenharmony_ci		pvt->info.rir_limit = haswell_rir_limit;
33208c2ecf20Sopenharmony_ci		pvt->info.sad_limit = sad_limit;
33218c2ecf20Sopenharmony_ci		pvt->info.interleave_mode = interleave_mode;
33228c2ecf20Sopenharmony_ci		pvt->info.dram_attr = dram_attr;
33238c2ecf20Sopenharmony_ci		pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule);
33248c2ecf20Sopenharmony_ci		pvt->info.interleave_list = ibridge_interleave_list;
33258c2ecf20Sopenharmony_ci		pvt->info.interleave_pkg = ibridge_interleave_pkg;
33268c2ecf20Sopenharmony_ci		pvt->info.get_width = ibridge_get_width;
33278c2ecf20Sopenharmony_ci
33288c2ecf20Sopenharmony_ci		/* Store pci devices at mci for faster access */
33298c2ecf20Sopenharmony_ci		rc = haswell_mci_bind_devs(mci, sbridge_dev);
33308c2ecf20Sopenharmony_ci		if (unlikely(rc < 0))
33318c2ecf20Sopenharmony_ci			goto fail0;
33328c2ecf20Sopenharmony_ci		get_source_id(mci);
33338c2ecf20Sopenharmony_ci		mci->ctl_name = kasprintf(GFP_KERNEL, "Haswell SrcID#%d_Ha#%d",
33348c2ecf20Sopenharmony_ci			pvt->sbridge_dev->source_id, pvt->sbridge_dev->dom);
33358c2ecf20Sopenharmony_ci		break;
33368c2ecf20Sopenharmony_ci	case BROADWELL:
33378c2ecf20Sopenharmony_ci		/* rankcfgr isn't used */
33388c2ecf20Sopenharmony_ci		pvt->info.get_tolm = haswell_get_tolm;
33398c2ecf20Sopenharmony_ci		pvt->info.get_tohm = haswell_get_tohm;
33408c2ecf20Sopenharmony_ci		pvt->info.dram_rule = ibridge_dram_rule;
33418c2ecf20Sopenharmony_ci		pvt->info.get_memory_type = haswell_get_memory_type;
33428c2ecf20Sopenharmony_ci		pvt->info.get_node_id = haswell_get_node_id;
33438c2ecf20Sopenharmony_ci		pvt->info.get_ha = ibridge_get_ha;
33448c2ecf20Sopenharmony_ci		pvt->info.rir_limit = haswell_rir_limit;
33458c2ecf20Sopenharmony_ci		pvt->info.sad_limit = sad_limit;
33468c2ecf20Sopenharmony_ci		pvt->info.interleave_mode = interleave_mode;
33478c2ecf20Sopenharmony_ci		pvt->info.dram_attr = dram_attr;
33488c2ecf20Sopenharmony_ci		pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule);
33498c2ecf20Sopenharmony_ci		pvt->info.interleave_list = ibridge_interleave_list;
33508c2ecf20Sopenharmony_ci		pvt->info.interleave_pkg = ibridge_interleave_pkg;
33518c2ecf20Sopenharmony_ci		pvt->info.get_width = broadwell_get_width;
33528c2ecf20Sopenharmony_ci
33538c2ecf20Sopenharmony_ci		/* Store pci devices at mci for faster access */
33548c2ecf20Sopenharmony_ci		rc = broadwell_mci_bind_devs(mci, sbridge_dev);
33558c2ecf20Sopenharmony_ci		if (unlikely(rc < 0))
33568c2ecf20Sopenharmony_ci			goto fail0;
33578c2ecf20Sopenharmony_ci		get_source_id(mci);
33588c2ecf20Sopenharmony_ci		mci->ctl_name = kasprintf(GFP_KERNEL, "Broadwell SrcID#%d_Ha#%d",
33598c2ecf20Sopenharmony_ci			pvt->sbridge_dev->source_id, pvt->sbridge_dev->dom);
33608c2ecf20Sopenharmony_ci		break;
33618c2ecf20Sopenharmony_ci	case KNIGHTS_LANDING:
33628c2ecf20Sopenharmony_ci		/* pvt->info.rankcfgr == ??? */
33638c2ecf20Sopenharmony_ci		pvt->info.get_tolm = knl_get_tolm;
33648c2ecf20Sopenharmony_ci		pvt->info.get_tohm = knl_get_tohm;
33658c2ecf20Sopenharmony_ci		pvt->info.dram_rule = knl_dram_rule;
33668c2ecf20Sopenharmony_ci		pvt->info.get_memory_type = knl_get_memory_type;
33678c2ecf20Sopenharmony_ci		pvt->info.get_node_id = knl_get_node_id;
33688c2ecf20Sopenharmony_ci		pvt->info.get_ha = knl_get_ha;
33698c2ecf20Sopenharmony_ci		pvt->info.rir_limit = NULL;
33708c2ecf20Sopenharmony_ci		pvt->info.sad_limit = knl_sad_limit;
33718c2ecf20Sopenharmony_ci		pvt->info.interleave_mode = knl_interleave_mode;
33728c2ecf20Sopenharmony_ci		pvt->info.dram_attr = dram_attr_knl;
33738c2ecf20Sopenharmony_ci		pvt->info.max_sad = ARRAY_SIZE(knl_dram_rule);
33748c2ecf20Sopenharmony_ci		pvt->info.interleave_list = knl_interleave_list;
33758c2ecf20Sopenharmony_ci		pvt->info.interleave_pkg = ibridge_interleave_pkg;
33768c2ecf20Sopenharmony_ci		pvt->info.get_width = knl_get_width;
33778c2ecf20Sopenharmony_ci
33788c2ecf20Sopenharmony_ci		rc = knl_mci_bind_devs(mci, sbridge_dev);
33798c2ecf20Sopenharmony_ci		if (unlikely(rc < 0))
33808c2ecf20Sopenharmony_ci			goto fail0;
33818c2ecf20Sopenharmony_ci		get_source_id(mci);
33828c2ecf20Sopenharmony_ci		mci->ctl_name = kasprintf(GFP_KERNEL, "Knights Landing SrcID#%d_Ha#%d",
33838c2ecf20Sopenharmony_ci			pvt->sbridge_dev->source_id, pvt->sbridge_dev->dom);
33848c2ecf20Sopenharmony_ci		break;
33858c2ecf20Sopenharmony_ci	}
33868c2ecf20Sopenharmony_ci
33878c2ecf20Sopenharmony_ci	if (!mci->ctl_name) {
33888c2ecf20Sopenharmony_ci		rc = -ENOMEM;
33898c2ecf20Sopenharmony_ci		goto fail0;
33908c2ecf20Sopenharmony_ci	}
33918c2ecf20Sopenharmony_ci
33928c2ecf20Sopenharmony_ci	/* Get dimm basic config and the memory layout */
33938c2ecf20Sopenharmony_ci	rc = get_dimm_config(mci);
33948c2ecf20Sopenharmony_ci	if (rc < 0) {
33958c2ecf20Sopenharmony_ci		edac_dbg(0, "MC: failed to get_dimm_config()\n");
33968c2ecf20Sopenharmony_ci		goto fail;
33978c2ecf20Sopenharmony_ci	}
33988c2ecf20Sopenharmony_ci	get_memory_layout(mci);
33998c2ecf20Sopenharmony_ci
34008c2ecf20Sopenharmony_ci	/* record ptr to the generic device */
34018c2ecf20Sopenharmony_ci	mci->pdev = &pdev->dev;
34028c2ecf20Sopenharmony_ci
34038c2ecf20Sopenharmony_ci	/* add this new MC control structure to EDAC's list of MCs */
34048c2ecf20Sopenharmony_ci	if (unlikely(edac_mc_add_mc(mci))) {
34058c2ecf20Sopenharmony_ci		edac_dbg(0, "MC: failed edac_mc_add_mc()\n");
34068c2ecf20Sopenharmony_ci		rc = -EINVAL;
34078c2ecf20Sopenharmony_ci		goto fail;
34088c2ecf20Sopenharmony_ci	}
34098c2ecf20Sopenharmony_ci
34108c2ecf20Sopenharmony_ci	return 0;
34118c2ecf20Sopenharmony_ci
34128c2ecf20Sopenharmony_cifail:
34138c2ecf20Sopenharmony_ci	kfree(mci->ctl_name);
34148c2ecf20Sopenharmony_cifail0:
34158c2ecf20Sopenharmony_ci	edac_mc_free(mci);
34168c2ecf20Sopenharmony_ci	sbridge_dev->mci = NULL;
34178c2ecf20Sopenharmony_ci	return rc;
34188c2ecf20Sopenharmony_ci}
34198c2ecf20Sopenharmony_ci
34208c2ecf20Sopenharmony_cistatic const struct x86_cpu_id sbridge_cpuids[] = {
34218c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE_X, &pci_dev_descr_sbridge_table),
34228c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE_X,	  &pci_dev_descr_ibridge_table),
34238c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(HASWELL_X,	  &pci_dev_descr_haswell_table),
34248c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_X,	  &pci_dev_descr_broadwell_table),
34258c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_D,	  &pci_dev_descr_broadwell_table),
34268c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNL,  &pci_dev_descr_knl_table),
34278c2ecf20Sopenharmony_ci	X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNM,  &pci_dev_descr_knl_table),
34288c2ecf20Sopenharmony_ci	{ }
34298c2ecf20Sopenharmony_ci};
34308c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(x86cpu, sbridge_cpuids);
34318c2ecf20Sopenharmony_ci
34328c2ecf20Sopenharmony_ci/*
34338c2ecf20Sopenharmony_ci *	sbridge_probe	Get all devices and register memory controllers
34348c2ecf20Sopenharmony_ci *			present.
34358c2ecf20Sopenharmony_ci *	return:
34368c2ecf20Sopenharmony_ci *		0 for FOUND a device
34378c2ecf20Sopenharmony_ci *		< 0 for error code
34388c2ecf20Sopenharmony_ci */
34398c2ecf20Sopenharmony_ci
34408c2ecf20Sopenharmony_cistatic int sbridge_probe(const struct x86_cpu_id *id)
34418c2ecf20Sopenharmony_ci{
34428c2ecf20Sopenharmony_ci	int rc = -ENODEV;
34438c2ecf20Sopenharmony_ci	u8 mc, num_mc = 0;
34448c2ecf20Sopenharmony_ci	struct sbridge_dev *sbridge_dev;
34458c2ecf20Sopenharmony_ci	struct pci_id_table *ptable = (struct pci_id_table *)id->driver_data;
34468c2ecf20Sopenharmony_ci
34478c2ecf20Sopenharmony_ci	/* get the pci devices we want to reserve for our use */
34488c2ecf20Sopenharmony_ci	rc = sbridge_get_all_devices(&num_mc, ptable);
34498c2ecf20Sopenharmony_ci
34508c2ecf20Sopenharmony_ci	if (unlikely(rc < 0)) {
34518c2ecf20Sopenharmony_ci		edac_dbg(0, "couldn't get all devices\n");
34528c2ecf20Sopenharmony_ci		goto fail0;
34538c2ecf20Sopenharmony_ci	}
34548c2ecf20Sopenharmony_ci
34558c2ecf20Sopenharmony_ci	mc = 0;
34568c2ecf20Sopenharmony_ci
34578c2ecf20Sopenharmony_ci	list_for_each_entry(sbridge_dev, &sbridge_edac_list, list) {
34588c2ecf20Sopenharmony_ci		edac_dbg(0, "Registering MC#%d (%d of %d)\n",
34598c2ecf20Sopenharmony_ci			 mc, mc + 1, num_mc);
34608c2ecf20Sopenharmony_ci
34618c2ecf20Sopenharmony_ci		sbridge_dev->mc = mc++;
34628c2ecf20Sopenharmony_ci		rc = sbridge_register_mci(sbridge_dev, ptable->type);
34638c2ecf20Sopenharmony_ci		if (unlikely(rc < 0))
34648c2ecf20Sopenharmony_ci			goto fail1;
34658c2ecf20Sopenharmony_ci	}
34668c2ecf20Sopenharmony_ci
34678c2ecf20Sopenharmony_ci	sbridge_printk(KERN_INFO, "%s\n", SBRIDGE_REVISION);
34688c2ecf20Sopenharmony_ci
34698c2ecf20Sopenharmony_ci	return 0;
34708c2ecf20Sopenharmony_ci
34718c2ecf20Sopenharmony_cifail1:
34728c2ecf20Sopenharmony_ci	list_for_each_entry(sbridge_dev, &sbridge_edac_list, list)
34738c2ecf20Sopenharmony_ci		sbridge_unregister_mci(sbridge_dev);
34748c2ecf20Sopenharmony_ci
34758c2ecf20Sopenharmony_ci	sbridge_put_all_devices();
34768c2ecf20Sopenharmony_cifail0:
34778c2ecf20Sopenharmony_ci	return rc;
34788c2ecf20Sopenharmony_ci}
34798c2ecf20Sopenharmony_ci
34808c2ecf20Sopenharmony_ci/*
34818c2ecf20Sopenharmony_ci *	sbridge_remove	cleanup
34828c2ecf20Sopenharmony_ci *
34838c2ecf20Sopenharmony_ci */
34848c2ecf20Sopenharmony_cistatic void sbridge_remove(void)
34858c2ecf20Sopenharmony_ci{
34868c2ecf20Sopenharmony_ci	struct sbridge_dev *sbridge_dev;
34878c2ecf20Sopenharmony_ci
34888c2ecf20Sopenharmony_ci	edac_dbg(0, "\n");
34898c2ecf20Sopenharmony_ci
34908c2ecf20Sopenharmony_ci	list_for_each_entry(sbridge_dev, &sbridge_edac_list, list)
34918c2ecf20Sopenharmony_ci		sbridge_unregister_mci(sbridge_dev);
34928c2ecf20Sopenharmony_ci
34938c2ecf20Sopenharmony_ci	/* Release PCI resources */
34948c2ecf20Sopenharmony_ci	sbridge_put_all_devices();
34958c2ecf20Sopenharmony_ci}
34968c2ecf20Sopenharmony_ci
34978c2ecf20Sopenharmony_ci/*
34988c2ecf20Sopenharmony_ci *	sbridge_init		Module entry function
34998c2ecf20Sopenharmony_ci *			Try to initialize this module for its devices
35008c2ecf20Sopenharmony_ci */
35018c2ecf20Sopenharmony_cistatic int __init sbridge_init(void)
35028c2ecf20Sopenharmony_ci{
35038c2ecf20Sopenharmony_ci	const struct x86_cpu_id *id;
35048c2ecf20Sopenharmony_ci	const char *owner;
35058c2ecf20Sopenharmony_ci	int rc;
35068c2ecf20Sopenharmony_ci
35078c2ecf20Sopenharmony_ci	edac_dbg(2, "\n");
35088c2ecf20Sopenharmony_ci
35098c2ecf20Sopenharmony_ci	owner = edac_get_owner();
35108c2ecf20Sopenharmony_ci	if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR)))
35118c2ecf20Sopenharmony_ci		return -EBUSY;
35128c2ecf20Sopenharmony_ci
35138c2ecf20Sopenharmony_ci	if (cpu_feature_enabled(X86_FEATURE_HYPERVISOR))
35148c2ecf20Sopenharmony_ci		return -ENODEV;
35158c2ecf20Sopenharmony_ci
35168c2ecf20Sopenharmony_ci	id = x86_match_cpu(sbridge_cpuids);
35178c2ecf20Sopenharmony_ci	if (!id)
35188c2ecf20Sopenharmony_ci		return -ENODEV;
35198c2ecf20Sopenharmony_ci
35208c2ecf20Sopenharmony_ci	/* Ensure that the OPSTATE is set correctly for POLL or NMI */
35218c2ecf20Sopenharmony_ci	opstate_init();
35228c2ecf20Sopenharmony_ci
35238c2ecf20Sopenharmony_ci	rc = sbridge_probe(id);
35248c2ecf20Sopenharmony_ci
35258c2ecf20Sopenharmony_ci	if (rc >= 0) {
35268c2ecf20Sopenharmony_ci		mce_register_decode_chain(&sbridge_mce_dec);
35278c2ecf20Sopenharmony_ci		return 0;
35288c2ecf20Sopenharmony_ci	}
35298c2ecf20Sopenharmony_ci
35308c2ecf20Sopenharmony_ci	sbridge_printk(KERN_ERR, "Failed to register device with error %d.\n",
35318c2ecf20Sopenharmony_ci		      rc);
35328c2ecf20Sopenharmony_ci
35338c2ecf20Sopenharmony_ci	return rc;
35348c2ecf20Sopenharmony_ci}
35358c2ecf20Sopenharmony_ci
35368c2ecf20Sopenharmony_ci/*
35378c2ecf20Sopenharmony_ci *	sbridge_exit()	Module exit function
35388c2ecf20Sopenharmony_ci *			Unregister the driver
35398c2ecf20Sopenharmony_ci */
35408c2ecf20Sopenharmony_cistatic void __exit sbridge_exit(void)
35418c2ecf20Sopenharmony_ci{
35428c2ecf20Sopenharmony_ci	edac_dbg(2, "\n");
35438c2ecf20Sopenharmony_ci	sbridge_remove();
35448c2ecf20Sopenharmony_ci	mce_unregister_decode_chain(&sbridge_mce_dec);
35458c2ecf20Sopenharmony_ci}
35468c2ecf20Sopenharmony_ci
35478c2ecf20Sopenharmony_cimodule_init(sbridge_init);
35488c2ecf20Sopenharmony_cimodule_exit(sbridge_exit);
35498c2ecf20Sopenharmony_ci
35508c2ecf20Sopenharmony_cimodule_param(edac_op_state, int, 0444);
35518c2ecf20Sopenharmony_ciMODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
35528c2ecf20Sopenharmony_ci
35538c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
35548c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mauro Carvalho Chehab");
35558c2ecf20Sopenharmony_ciMODULE_AUTHOR("Red Hat Inc. (https://www.redhat.com)");
35568c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MC Driver for Intel Sandy Bridge and Ivy Bridge memory controllers - "
35578c2ecf20Sopenharmony_ci		   SBRIDGE_REVISION);
3558