diff options
Diffstat (limited to 'drivers/edac/sb_edac.c')
| -rw-r--r-- | drivers/edac/sb_edac.c | 810 | 
1 files changed, 541 insertions, 269 deletions
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index deea0dc9999b..0034c4844428 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -99,6 +99,7 @@ static const u32 ibridge_dram_rule[] = {  #define DRAM_ATTR(reg)		GET_BITFIELD(reg, 2,  3)  #define INTERLEAVE_MODE(reg)	GET_BITFIELD(reg, 1,  1)  #define DRAM_RULE_ENABLE(reg)	GET_BITFIELD(reg, 0,  0) +#define A7MODE(reg)		GET_BITFIELD(reg, 26, 26)  static char *get_dram_attr(u32 reg)  { @@ -164,6 +165,8 @@ static inline int sad_pkg(const struct interleave_pkg *table, u32 reg,  #define TOLM		0x80  #define	TOHM		0x84 +#define HASWELL_TOHM_0	0xd4 +#define HASWELL_TOHM_1	0xd8  #define GET_TOLM(reg)		((GET_BITFIELD(reg, 0,  3) << 28) | 0x3ffffff)  #define GET_TOHM(reg)		((GET_BITFIELD(reg, 0, 20) << 25) | 0x3ffffff) @@ -176,8 +179,6 @@ static inline int sad_pkg(const struct interleave_pkg *table, u32 reg,  #define SAD_CONTROL	0xf4 -#define NODE_ID(reg)		GET_BITFIELD(reg, 0, 2) -  /* Device 14 function 0 */  static const u32 tad_dram_rule[] = { @@ -235,7 +236,6 @@ static const u32 rir_way_limit[] = {  #define IS_RIR_VALID(reg)	GET_BITFIELD(reg, 31, 31)  #define RIR_WAY(reg)		GET_BITFIELD(reg, 28, 29) -#define RIR_LIMIT(reg)		((GET_BITFIELD(reg,  1, 10) << 29)| 0x1fffffff)  #define MAX_RIR_WAY	8 @@ -279,8 +279,6 @@ static const u32 correrrthrsld[] = {  #define IB_RANK_CFG_A		0x0320 -#define IS_RDIMM_ENABLED(reg)		GET_BITFIELD(reg, 11, 11) -  /*   * sbridge structs   */ @@ -291,6 +289,7 @@ static const u32 correrrthrsld[] = {  enum type {  	SANDY_BRIDGE,  	IVY_BRIDGE, +	HASWELL,  };  struct sbridge_pvt; @@ -300,11 +299,15 @@ struct sbridge_info {  	u32		rankcfgr;  	u64		(*get_tolm)(struct sbridge_pvt *pvt);  	u64		(*get_tohm)(struct sbridge_pvt *pvt); +	u64		(*rir_limit)(u32 reg);  	const u32	*dram_rule;  	const u32	*interleave_list;  	const struct interleave_pkg *interleave_pkg;  	u8		max_sad;  	u8		max_interleave; +	u8		(*get_node_id)(struct sbridge_pvt *pvt); +	enum mem_type	(*get_memory_type)(struct sbridge_pvt *pvt); +	struct pci_dev	*pci_vtd;  };  struct sbridge_channel { @@ -313,9 +316,7 @@ struct sbridge_channel {  };  struct pci_id_descr { -	int			dev; -	int			func; -	int 			dev_id; +	int			dev_id;  	int			optional;  }; @@ -338,6 +339,7 @@ struct sbridge_pvt {  	struct pci_dev		*pci_sad0, *pci_sad1;  	struct pci_dev		*pci_ha0, *pci_ha1;  	struct pci_dev		*pci_br0, *pci_br1; +	struct pci_dev		*pci_ha1_ta;  	struct pci_dev		*pci_tad[NUM_CHANNELS];  	struct sbridge_dev	*sbridge_dev; @@ -362,31 +364,29 @@ struct sbridge_pvt {  	u64			tolm, tohm;  }; -#define PCI_DESCR(device, function, device_id, opt)	\ -	.dev = (device),				\ -	.func = (function),				\ -	.dev_id = (device_id),				\ +#define PCI_DESCR(device_id, opt)	\ +	.dev_id = (device_id),		\  	.optional = opt  static const struct pci_id_descr pci_dev_descr_sbridge[] = {  		/* Processor Home Agent */ -	{ PCI_DESCR(14, 0, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0, 0)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0, 0)	},  		/* Memory controller */ -	{ PCI_DESCR(15, 0, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA, 0)	}, -	{ PCI_DESCR(15, 1, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS, 0)	}, -	{ PCI_DESCR(15, 2, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0, 0)	}, -	{ PCI_DESCR(15, 3, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1, 0)	}, -	{ PCI_DESCR(15, 4, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2, 0)	}, -	{ PCI_DESCR(15, 5, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3, 0)	}, -	{ PCI_DESCR(17, 0, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO, 1)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA, 0)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS, 0)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0, 0)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1, 0)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2, 0)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3, 0)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO, 1)	},  		/* System Address Decoder */ -	{ PCI_DESCR(12, 6, PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0, 0)		}, -	{ PCI_DESCR(12, 7, PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1, 0)		}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0, 0)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1, 0)	},  		/* Broadcast Registers */ -	{ PCI_DESCR(13, 6, PCI_DEVICE_ID_INTEL_SBRIDGE_BR, 0)		}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_BR, 0)		},  };  #define PCI_ID_TABLE_ENTRY(A) { .descr=A, .n_devs = ARRAY_SIZE(A) } @@ -423,34 +423,34 @@ static const struct pci_id_table pci_dev_descr_sbridge_table[] = {  static const struct pci_id_descr pci_dev_descr_ibridge[] = {  		/* Processor Home Agent */ -	{ PCI_DESCR(14, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0, 0)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0, 0)		},  		/* Memory controller */ -	{ PCI_DESCR(15, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA, 0)	}, -	{ PCI_DESCR(15, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS, 0)	}, -	{ PCI_DESCR(15, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0, 0)	}, -	{ PCI_DESCR(15, 3, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1, 0)	}, -	{ PCI_DESCR(15, 4, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2, 0)	}, -	{ PCI_DESCR(15, 5, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3, 0)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA, 0)		}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS, 0)		}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0, 0)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1, 0)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2, 0)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3, 0)	},  		/* System Address Decoder */ -	{ PCI_DESCR(22, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_SAD, 0)		}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_SAD, 0)			},  		/* Broadcast Registers */ -	{ PCI_DESCR(22, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_BR0, 1)		}, -	{ PCI_DESCR(22, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_BR1, 0)		}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_BR0, 1)			}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_BR1, 0)			},  		/* Optional, mode 2HA */ -	{ PCI_DESCR(28, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1, 1)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1, 1)		},  #if 0 -	{ PCI_DESCR(29, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA, 1)	}, -	{ PCI_DESCR(29, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS, 1)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA, 1)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS, 1)	},  #endif -	{ PCI_DESCR(29, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0, 1)	}, -	{ PCI_DESCR(29, 3, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1, 1)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0, 1)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1, 1)	}, -	{ PCI_DESCR(17, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0, 1) }, -	{ PCI_DESCR(17, 4, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0, 1) }, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0, 1)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0, 1)	},  };  static const struct pci_id_table pci_dev_descr_ibridge_table[] = { @@ -458,12 +458,80 @@ static const struct pci_id_table pci_dev_descr_ibridge_table[] = {  	{0,}			/* 0 terminated list. */  }; +/* Haswell support */ +/* EN processor: + *	- 1 IMC + *	- 3 DDR3 channels, 2 DPC per channel + * EP processor: + *	- 1 or 2 IMC + *	- 4 DDR4 channels, 3 DPC per channel + * EP 4S processor: + *	- 2 IMC + *	- 4 DDR4 channels, 3 DPC per channel + * EX processor: + *	- 2 IMC + *	- each IMC interfaces with a SMI 2 channel + *	- each SMI channel interfaces with a scalable memory buffer + *	- each scalable memory buffer supports 4 DDR3/DDR4 channels, 3 DPC + */ +#define HASWELL_DDRCRCLKCONTROLS 0xa10 +#define HASWELL_HASYSDEFEATURE2 0x84 +#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_VTD_MISC 0x2f28 +#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0	0x2fa0 +#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1	0x2f60 +#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA	0x2fa8 +#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_THERMAL 0x2f71 +#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA	0x2f68 +#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_THERMAL 0x2f79 +#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD0 0x2ffc +#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD1 0x2ffd +#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD0 0x2faa +#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD1 0x2fab +#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD2 0x2fac +#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3 0x2fad +#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD0 0x2f6a +#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD1 0x2f6b +#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD2 0x2f6c +#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD3 0x2f6d +#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0 0x2fbd +static const struct pci_id_descr pci_dev_descr_haswell[] = { +	/* first item must be the HA */ +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0, 0)		}, + +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD0, 0)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD1, 0)	}, + +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1, 1)		}, + +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA, 0)		}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_THERMAL, 0)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD0, 0)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD1, 0)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD2, 1)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3, 1)	}, + +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0, 1)		}, + +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA, 1)		}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_THERMAL, 1)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD0, 1)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD1, 1)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD2, 1)	}, +	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD3, 1)	}, +}; + +static const struct pci_id_table pci_dev_descr_haswell_table[] = { +	PCI_ID_TABLE_ENTRY(pci_dev_descr_haswell), +	{0,}			/* 0 terminated list. */ +}; +  /*   *	pci_device_id	table for which devices we are looking for   */  static const struct pci_device_id sbridge_pci_tbl[] = {  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA)},  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)}, +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0)},  	{0,}			/* 0 terminated list. */  }; @@ -472,13 +540,17 @@ static const struct pci_device_id sbridge_pci_tbl[] = {  			Ancillary status routines   ****************************************************************************/ -static inline int numrank(u32 mtr) +static inline int numrank(enum type type, u32 mtr)  {  	int ranks = (1 << RANK_CNT_BITS(mtr)); +	int max = 4; -	if (ranks > 4) { -		edac_dbg(0, "Invalid number of ranks: %d (max = 4) raw value = %x (%04x)\n", -			 ranks, (unsigned int)RANK_CNT_BITS(mtr), mtr); +	if (type == HASWELL) +		max = 8; + +	if (ranks > max) { +		edac_dbg(0, "Invalid number of ranks: %d (max = %i) raw value = %x (%04x)\n", +			 ranks, max, (unsigned int)RANK_CNT_BITS(mtr), mtr);  		return -EINVAL;  	} @@ -588,10 +660,107 @@ static u64 ibridge_get_tohm(struct sbridge_pvt *pvt)  	return GET_TOHM(reg);  } +static u64 rir_limit(u32 reg) +{ +	return ((u64)GET_BITFIELD(reg,  1, 10) << 29) | 0x1fffffff; +} + +static enum mem_type get_memory_type(struct sbridge_pvt *pvt) +{ +	u32 reg; +	enum mem_type mtype; + +	if (pvt->pci_ddrio) { +		pci_read_config_dword(pvt->pci_ddrio, pvt->info.rankcfgr, +				      ®); +		if (GET_BITFIELD(reg, 11, 11)) +			/* FIXME: Can also be LRDIMM */ +			mtype = MEM_RDDR3; +		else +			mtype = MEM_DDR3; +	} else +		mtype = MEM_UNKNOWN; + +	return mtype; +} + +static enum mem_type haswell_get_memory_type(struct sbridge_pvt *pvt) +{ +	u32 reg; +	bool registered = false; +	enum mem_type mtype = MEM_UNKNOWN; + +	if (!pvt->pci_ddrio) +		goto out; + +	pci_read_config_dword(pvt->pci_ddrio, +			      HASWELL_DDRCRCLKCONTROLS, ®); +	/* Is_Rdimm */ +	if (GET_BITFIELD(reg, 16, 16)) +		registered = true; + +	pci_read_config_dword(pvt->pci_ta, MCMTR, ®); +	if (GET_BITFIELD(reg, 14, 14)) { +		if (registered) +			mtype = MEM_RDDR4; +		else +			mtype = MEM_DDR4; +	} else { +		if (registered) +			mtype = MEM_RDDR3; +		else +			mtype = MEM_DDR3; +	} + +out: +	return mtype; +} + +static u8 get_node_id(struct sbridge_pvt *pvt) +{ +	u32 reg; +	pci_read_config_dword(pvt->pci_br0, SAD_CONTROL, ®); +	return GET_BITFIELD(reg, 0, 2); +} + +static u8 haswell_get_node_id(struct sbridge_pvt *pvt) +{ +	u32 reg; + +	pci_read_config_dword(pvt->pci_sad1, SAD_CONTROL, ®); +	return GET_BITFIELD(reg, 0, 3); +} + +static u64 haswell_get_tolm(struct sbridge_pvt *pvt) +{ +	u32 reg; + +	pci_read_config_dword(pvt->info.pci_vtd, TOLM, ®); +	return (GET_BITFIELD(reg, 26, 31) << 26) | 0x1ffffff; +} + +static u64 haswell_get_tohm(struct sbridge_pvt *pvt) +{ +	u64 rc; +	u32 reg; + +	pci_read_config_dword(pvt->info.pci_vtd, HASWELL_TOHM_0, ®); +	rc = GET_BITFIELD(reg, 26, 31); +	pci_read_config_dword(pvt->info.pci_vtd, HASWELL_TOHM_1, ®); +	rc = ((reg << 6) | rc) << 26; + +	return rc | 0x1ffffff; +} + +static u64 haswell_rir_limit(u32 reg) +{ +	return (((u64)GET_BITFIELD(reg,  1, 11) + 1) << 29) - 1; +} +  static inline u8 sad_pkg_socket(u8 pkg)  {  	/* on Ivy Bridge, nodeID is SASS, where A is HA and S is node id */ -	return (pkg >> 3) | (pkg & 0x3); +	return ((pkg >> 3) << 2) | (pkg & 0x3);  }  static inline u8 sad_pkg_ha(u8 pkg) @@ -602,44 +771,43 @@ static inline u8 sad_pkg_ha(u8 pkg)  /****************************************************************************  			Memory check routines   ****************************************************************************/ -static struct pci_dev *get_pdev_slot_func(u8 bus, unsigned slot, -					  unsigned func) +static struct pci_dev *get_pdev_same_bus(u8 bus, u32 id)  { -	struct sbridge_dev *sbridge_dev = get_sbridge_dev(bus); -	int i; - -	if (!sbridge_dev) -		return NULL; - -	for (i = 0; i < sbridge_dev->n_devs; i++) { -		if (!sbridge_dev->pdev[i]) -			continue; +	struct pci_dev *pdev = NULL; -		if (PCI_SLOT(sbridge_dev->pdev[i]->devfn) == slot && -		    PCI_FUNC(sbridge_dev->pdev[i]->devfn) == func) { -			edac_dbg(1, "Associated %02x.%02x.%d with %p\n", -				 bus, slot, func, sbridge_dev->pdev[i]); -			return sbridge_dev->pdev[i]; -		} -	} +	do { +		pdev = pci_get_device(PCI_VENDOR_ID_INTEL, id, pdev); +		if (pdev && pdev->bus->number == bus) +			break; +	} while (pdev); -	return NULL; +	return pdev;  }  /**   * check_if_ecc_is_active() - Checks if ECC is active - * bus:		Device bus + * @bus:	Device bus + * @type:	Memory controller type + * returns: 0 in case ECC is active, -ENODEV if it can't be determined or + *	    disabled   */ -static int check_if_ecc_is_active(const u8 bus) +static int check_if_ecc_is_active(const u8 bus, enum type type)  {  	struct pci_dev *pdev = NULL; -	u32 mcmtr; +	u32 mcmtr, id; + +	if (type == IVY_BRIDGE) +		id = PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA; +	else if (type == HASWELL) +		id = PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA; +	else +		id = PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA; -	pdev = get_pdev_slot_func(bus, 15, 0); +	pdev = get_pdev_same_bus(bus, id);  	if (!pdev) {  		sbridge_printk(KERN_ERR, "Couldn't find PCI device " -					"%2x.%02d.%d!!!\n", -					bus, 15, 0); +					"%04x:%04x! on bus %02d\n", +					PCI_VENDOR_ID_INTEL, id, bus);  		return -ENODEV;  	} @@ -661,11 +829,14 @@ static int get_dimm_config(struct mem_ctl_info *mci)  	enum edac_type mode;  	enum mem_type mtype; -	pci_read_config_dword(pvt->pci_br0, SAD_TARGET, ®); +	if (pvt->info.type == HASWELL) +		pci_read_config_dword(pvt->pci_sad1, SAD_TARGET, ®); +	else +		pci_read_config_dword(pvt->pci_br0, SAD_TARGET, ®); +  	pvt->sbridge_dev->source_id = SOURCE_ID(reg); -	pci_read_config_dword(pvt->pci_br0, SAD_CONTROL, ®); -	pvt->sbridge_dev->node_id = NODE_ID(reg); +	pvt->sbridge_dev->node_id = pvt->info.get_node_id(pvt);  	edac_dbg(0, "mc#%d: Node ID: %d, source ID: %d\n",  		 pvt->sbridge_dev->mc,  		 pvt->sbridge_dev->node_id, @@ -698,24 +869,18 @@ static int get_dimm_config(struct mem_ctl_info *mci)  		pvt->is_close_pg = false;  	} -	if (pvt->pci_ddrio) { -		pci_read_config_dword(pvt->pci_ddrio, pvt->info.rankcfgr, -				      ®); -		if (IS_RDIMM_ENABLED(reg)) { -			/* FIXME: Can also be LRDIMM */ -			edac_dbg(0, "Memory is registered\n"); -			mtype = MEM_RDDR3; -		} else { -			edac_dbg(0, "Memory is unregistered\n"); -			mtype = MEM_DDR3; -		} -	} else { +	mtype = pvt->info.get_memory_type(pvt); +	if (mtype == MEM_RDDR3 || mtype == MEM_RDDR4) +		edac_dbg(0, "Memory is registered\n"); +	else if (mtype == MEM_UNKNOWN)  		edac_dbg(0, "Cannot determine memory type\n"); -		mtype = MEM_UNKNOWN; -	} +	else +		edac_dbg(0, "Memory is unregistered\n"); -	/* On all supported DDR3 DIMM types, there are 8 banks available */ -	banks = 8; +	if (mtype == MEM_DDR4 || MEM_RDDR4) +		banks = 16; +	else +		banks = 8;  	for (i = 0; i < NUM_CHANNELS; i++) {  		u32 mtr; @@ -729,11 +894,10 @@ static int get_dimm_config(struct mem_ctl_info *mci)  			if (IS_DIMM_PRESENT(mtr)) {  				pvt->channel[i].dimms++; -				ranks = numrank(mtr); +				ranks = numrank(pvt->info.type, mtr);  				rows = numrow(mtr);  				cols = numcol(mtr); -				/* DDR3 has 8 I/O banks */  				size = ((u64)rows * cols * banks * ranks) >> (20 - 3);  				npages = MiB_TO_PAGES(size); @@ -744,7 +908,17 @@ static int get_dimm_config(struct mem_ctl_info *mci)  				dimm->nr_pages = npages;  				dimm->grain = 32; -				dimm->dtype = (banks == 8) ? DEV_X8 : DEV_X4; +				switch (banks) { +				case 16: +					dimm->dtype = DEV_X16; +					break; +				case 8: +					dimm->dtype = DEV_X8; +					break; +				case 4: +					dimm->dtype = DEV_X4; +					break; +				}  				dimm->mtype = mtype;  				dimm->edac_mode = mode;  				snprintf(dimm->label, sizeof(dimm->label), @@ -887,7 +1061,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci)  			if (!IS_RIR_VALID(reg))  				continue; -			tmp_mb = RIR_LIMIT(reg) >> 20; +			tmp_mb = pvt->info.rir_limit(reg) >> 20;  			rir_way = 1 << RIR_WAY(reg);  			mb = div_u64_rem(tmp_mb, 1000, &kb);  			edac_dbg(0, "CH#%d RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d, reg=0x%08x\n", @@ -936,11 +1110,11 @@ static int get_memory_error_data(struct mem_ctl_info *mci,  	struct mem_ctl_info	*new_mci;  	struct sbridge_pvt *pvt = mci->pvt_info;  	struct pci_dev		*pci_ha; -	int 			n_rir, n_sads, n_tads, sad_way, sck_xch; +	int			n_rir, n_sads, n_tads, sad_way, sck_xch;  	int			sad_interl, idx, base_ch; -	int			interleave_mode; +	int			interleave_mode, shiftup = 0;  	unsigned		sad_interleave[pvt->info.max_interleave]; -	u32			reg; +	u32			reg, dram_rule;  	u8			ch_way, sck_way, pkg, sad_ha = 0;  	u32			tad_offset;  	u32			rir_way; @@ -987,8 +1161,9 @@ static int get_memory_error_data(struct mem_ctl_info *mci,  		sprintf(msg, "Can't discover the memory socket");  		return -EINVAL;  	} -	*area_type = get_dram_attr(reg); -	interleave_mode = INTERLEAVE_MODE(reg); +	dram_rule = reg; +	*area_type = get_dram_attr(dram_rule); +	interleave_mode = INTERLEAVE_MODE(dram_rule);  	pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads],  			      ®); @@ -1033,6 +1208,36 @@ static int get_memory_error_data(struct mem_ctl_info *mci,  		*socket = sad_interleave[idx];  		edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n",  			 idx, sad_way, *socket); +	} else if (pvt->info.type == HASWELL) { +		int bits, a7mode = A7MODE(dram_rule); + +		if (a7mode) { +			/* A7 mode swaps P9 with P6 */ +			bits = GET_BITFIELD(addr, 7, 8) << 1; +			bits |= GET_BITFIELD(addr, 9, 9); +		} else +			bits = GET_BITFIELD(addr, 7, 9); + +		if (interleave_mode) { +			/* interleave mode will XOR {8,7,6} with {18,17,16} */ +			idx = GET_BITFIELD(addr, 16, 18); +			idx ^= bits; +		} else +			idx = bits; + +		pkg = sad_pkg(pvt->info.interleave_pkg, reg, idx); +		*socket = sad_pkg_socket(pkg); +		sad_ha = sad_pkg_ha(pkg); + +		if (a7mode) { +			/* MCChanShiftUpEnable */ +			pci_read_config_dword(pvt->pci_ha0, +					      HASWELL_HASYSDEFEATURE2, ®); +			shiftup = GET_BITFIELD(reg, 22, 22); +		} + +		edac_dbg(0, "SAD interleave package: %d = CPU socket %d, HA %i, shiftup: %i\n", +			 idx, *socket, sad_ha, shiftup);  	} else {  		/* Ivy Bridge's SAD mode doesn't support XOR interleave mode */  		idx = (addr >> 6) & 7; @@ -1090,7 +1295,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,  	if (ch_way == 3)  		idx = addr >> 6;  	else -		idx = addr >> (6 + sck_way); +		idx = (addr >> (6 + sck_way + shiftup)) & 0x3;  	idx = idx % ch_way;  	/* @@ -1181,7 +1386,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,  		if (!IS_RIR_VALID(reg))  			continue; -		limit = RIR_LIMIT(reg); +		limit = pvt->info.rir_limit(reg);  		mb = div_u64_rem(limit >> 20, 1000, &kb);  		edac_dbg(0, "RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d\n",  			 n_rir, @@ -1197,6 +1402,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,  		return -EINVAL;  	}  	rir_way = RIR_WAY(reg); +  	if (pvt->is_close_pg)  		idx = (ch_addr >> 6);  	else @@ -1259,13 +1465,11 @@ static int sbridge_get_onedevice(struct pci_dev **prev,  {  	struct sbridge_dev *sbridge_dev;  	const struct pci_id_descr *dev_descr = &table->descr[devno]; -  	struct pci_dev *pdev = NULL;  	u8 bus = 0;  	sbridge_printk(KERN_DEBUG, -		"Seeking for: dev %02x.%d PCI ID %04x:%04x\n", -		dev_descr->dev, dev_descr->func, +		"Seeking for: PCI ID %04x:%04x\n",  		PCI_VENDOR_ID_INTEL, dev_descr->dev_id);  	pdev = pci_get_device(PCI_VENDOR_ID_INTEL, @@ -1280,12 +1484,12 @@ static int sbridge_get_onedevice(struct pci_dev **prev,  		if (dev_descr->optional)  			return 0; +		/* if the HA wasn't found */  		if (devno == 0)  			return -ENODEV;  		sbridge_printk(KERN_INFO, -			"Device not found: dev %02x.%d PCI ID %04x:%04x\n", -			dev_descr->dev, dev_descr->func, +			"Device not found: %04x:%04x\n",  			PCI_VENDOR_ID_INTEL, dev_descr->dev_id);  		/* End of list, leave */ @@ -1305,9 +1509,7 @@ static int sbridge_get_onedevice(struct pci_dev **prev,  	if (sbridge_dev->pdev[devno]) {  		sbridge_printk(KERN_ERR, -			"Duplicated device for " -			"dev %02x:%d.%d PCI ID %04x:%04x\n", -			bus, dev_descr->dev, dev_descr->func, +			"Duplicated device for %04x:%04x\n",  			PCI_VENDOR_ID_INTEL, dev_descr->dev_id);  		pci_dev_put(pdev);  		return -ENODEV; @@ -1315,30 +1517,15 @@ static int sbridge_get_onedevice(struct pci_dev **prev,  	sbridge_dev->pdev[devno] = pdev; -	/* Sanity check */ -	if (unlikely(PCI_SLOT(pdev->devfn) != dev_descr->dev || -			PCI_FUNC(pdev->devfn) != dev_descr->func)) { -		sbridge_printk(KERN_ERR, -			"Device PCI ID %04x:%04x " -			"has dev %02x:%d.%d instead of dev %02x:%02x.%d\n", -			PCI_VENDOR_ID_INTEL, dev_descr->dev_id, -			bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), -			bus, dev_descr->dev, dev_descr->func); -		return -ENODEV; -	} -  	/* Be sure that the device is enabled */  	if (unlikely(pci_enable_device(pdev) < 0)) {  		sbridge_printk(KERN_ERR, -			"Couldn't enable " -			"dev %02x:%d.%d PCI ID %04x:%04x\n", -			bus, dev_descr->dev, dev_descr->func, +			"Couldn't enable %04x:%04x\n",  			PCI_VENDOR_ID_INTEL, dev_descr->dev_id);  		return -ENODEV;  	} -	edac_dbg(0, "Detected dev %02x:%d.%d PCI ID %04x:%04x\n", -		 bus, dev_descr->dev, dev_descr->func, +	edac_dbg(0, "Detected %04x:%04x\n",  		 PCI_VENDOR_ID_INTEL, dev_descr->dev_id);  	/* @@ -1355,10 +1542,9 @@ static int sbridge_get_onedevice(struct pci_dev **prev,  /*   * sbridge_get_all_devices - Find and perform 'get' operation on the MCH's - *			     device/functions we want to reference for this driver. - *			     Need to 'get' device 16 func 1 and func 2. + *			     devices we want to reference for this driver.   * @num_mc: pointer to the memory controllers count, to be incremented in case - * 	    of success. + *	    of success.   * @table: model specific table   *   * returns 0 in case of success or error code @@ -1396,79 +1582,51 @@ static int sbridge_mci_bind_devs(struct mem_ctl_info *mci,  {  	struct sbridge_pvt *pvt = mci->pvt_info;  	struct pci_dev *pdev; -	int i, func, slot; +	int i;  	for (i = 0; i < sbridge_dev->n_devs; i++) {  		pdev = sbridge_dev->pdev[i];  		if (!pdev)  			continue; -		slot = PCI_SLOT(pdev->devfn); -		func = PCI_FUNC(pdev->devfn); -		switch (slot) { -		case 12: -			switch (func) { -			case 6: -				pvt->pci_sad0 = pdev; -				break; -			case 7: -				pvt->pci_sad1 = pdev; -				break; -			default: -				goto error; -			} + +		switch (pdev->device) { +		case PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0: +			pvt->pci_sad0 = pdev;  			break; -		case 13: -			switch (func) { -			case 6: -				pvt->pci_br0 = pdev; -				break; -			default: -				goto error; -			} +		case PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1: +			pvt->pci_sad1 = pdev;  			break; -		case 14: -			switch (func) { -			case 0: -				pvt->pci_ha0 = pdev; -				break; -			default: -				goto error; -			} +		case PCI_DEVICE_ID_INTEL_SBRIDGE_BR: +			pvt->pci_br0 = pdev;  			break; -		case 15: -			switch (func) { -			case 0: -				pvt->pci_ta = pdev; -				break; -			case 1: -				pvt->pci_ras = pdev; -				break; -			case 2: -			case 3: -			case 4: -			case 5: -				pvt->pci_tad[func - 2] = pdev; -				break; -			default: -				goto error; -			} +		case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0: +			pvt->pci_ha0 = pdev;  			break; -		case 17: -			switch (func) { -			case 0: -				pvt->pci_ddrio = pdev; -				break; -			default: -				goto error; -			} +		case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA: +			pvt->pci_ta = pdev; +			break; +		case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS: +			pvt->pci_ras = pdev; +			break; +		case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0: +		case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1: +		case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2: +		case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3: +		{ +			int id = pdev->device - PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0; +			pvt->pci_tad[id] = pdev; +		} +			break; +		case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO: +			pvt->pci_ddrio = pdev;  			break;  		default:  			goto error;  		} -		edac_dbg(0, "Associated PCI %02x.%02d.%d with dev = %p\n", +		edac_dbg(0, "Associated PCI %02x:%02x, bus %d with dev = %p\n", +			 pdev->vendor, pdev->device,  			 sbridge_dev->bus, -			 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),  			 pdev);  	} @@ -1488,9 +1646,8 @@ enodev:  	return -ENODEV;  error: -	sbridge_printk(KERN_ERR, "Device %d, function %d " -		      "is out of the expected range\n", -		      slot, func); +	sbridge_printk(KERN_ERR, "Unexpected device %02x:%02x\n", +		       PCI_VENDOR_ID_INTEL, pdev->device);  	return -EINVAL;  } @@ -1499,7 +1656,7 @@ static int ibridge_mci_bind_devs(struct mem_ctl_info *mci,  {  	struct sbridge_pvt *pvt = mci->pvt_info;  	struct pci_dev *pdev, *tmp; -	int i, func, slot; +	int i;  	bool mode_2ha = false;  	tmp = pci_get_device(PCI_VENDOR_ID_INTEL, @@ -1513,79 +1670,60 @@ static int ibridge_mci_bind_devs(struct mem_ctl_info *mci,  		pdev = sbridge_dev->pdev[i];  		if (!pdev)  			continue; -		slot = PCI_SLOT(pdev->devfn); -		func = PCI_FUNC(pdev->devfn); -		switch (slot) { -		case 14: -			if (func == 0) { -				pvt->pci_ha0 = pdev; -				break; -			} -			goto error; -		case 15: -			switch (func) { -			case 0: -				pvt->pci_ta = pdev; -				break; -			case 1: -				pvt->pci_ras = pdev; -				break; -			case 4: -			case 5: -				/* if we have 2 HAs active, channels 2 and 3 -				 * are in other device */ -				if (mode_2ha) -					break; -				/* fall through */ -			case 2: -			case 3: -				pvt->pci_tad[func - 2] = pdev; +		switch (pdev->device) { +		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0: +			pvt->pci_ha0 = pdev; +			break; +		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA: +			pvt->pci_ta = pdev; +		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS: +			pvt->pci_ras = pdev; +			break; +		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2: +		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3: +			/* if we have 2 HAs active, channels 2 and 3 +			 * are in other device */ +			if (mode_2ha)  				break; -			default: -				goto error; -			} +			/* fall through */ +		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0: +		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1: +		{ +			int id = pdev->device - PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0; +			pvt->pci_tad[id] = pdev; +		}  			break; -		case 17: -			if (func == 4) { +		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0: +			pvt->pci_ddrio = pdev; +			break; +		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0: +			if (!mode_2ha)  				pvt->pci_ddrio = pdev; -				break; -			} else if (func == 0) { -				if (!mode_2ha) -					pvt->pci_ddrio = pdev; -				break; -			} -			goto error; -		case 22: -			switch (func) { -			case 0: -				pvt->pci_sad0 = pdev; -				break; -			case 1: -				pvt->pci_br0 = pdev; -				break; -			case 2: -				pvt->pci_br1 = pdev; -				break; -			default: -				goto error; -			}  			break; -		case 28: -			if (func == 0) { -				pvt->pci_ha1 = pdev; -				break; -			} -			goto error; -		case 29: +		case PCI_DEVICE_ID_INTEL_IBRIDGE_SAD: +			pvt->pci_sad0 = pdev; +			break; +		case PCI_DEVICE_ID_INTEL_IBRIDGE_BR0: +			pvt->pci_br0 = pdev; +			break; +		case PCI_DEVICE_ID_INTEL_IBRIDGE_BR1: +			pvt->pci_br1 = pdev; +			break; +		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1: +			pvt->pci_ha1 = pdev; +			break; +		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0: +		case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1: +		{ +			int id = pdev->device - PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0 + 2; +  			/* we shouldn't have this device if we have just one  			 * HA present */  			WARN_ON(!mode_2ha); -			if (func == 2 || func == 3) { -				pvt->pci_tad[func] = pdev; -				break; -			} -			goto error; +			pvt->pci_tad[id] = pdev; +		} +			break;  		default:  			goto error;  		} @@ -1614,11 +1752,111 @@ enodev:  error:  	sbridge_printk(KERN_ERR, -		       "Device %d, function %d is out of the expected range\n", -		       slot, func); +		       "Unexpected device %02x:%02x\n", PCI_VENDOR_ID_INTEL, +			pdev->device);  	return -EINVAL;  } +static int haswell_mci_bind_devs(struct mem_ctl_info *mci, +				 struct sbridge_dev *sbridge_dev) +{ +	struct sbridge_pvt *pvt = mci->pvt_info; +	struct pci_dev *pdev, *tmp; +	int i; +	bool mode_2ha = false; + +	tmp = pci_get_device(PCI_VENDOR_ID_INTEL, +			     PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1, NULL); +	if (tmp) { +		mode_2ha = true; +		pci_dev_put(tmp); +	} + +	/* there's only one device per system; not tied to any bus */ +	if (pvt->info.pci_vtd == NULL) +		/* result will be checked later */ +		pvt->info.pci_vtd = pci_get_device(PCI_VENDOR_ID_INTEL, +						   PCI_DEVICE_ID_INTEL_HASWELL_IMC_VTD_MISC, +						   NULL); + +	for (i = 0; i < sbridge_dev->n_devs; i++) { +		pdev = sbridge_dev->pdev[i]; +		if (!pdev) +			continue; + +		switch (pdev->device) { +		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD0: +			pvt->pci_sad0 = pdev; +			break; +		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD1: +			pvt->pci_sad1 = pdev; +			break; +		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0: +			pvt->pci_ha0 = pdev; +			break; +		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA: +			pvt->pci_ta = pdev; +			break; +		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_THERMAL: +			pvt->pci_ras = pdev; +			break; +		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD0: +			pvt->pci_tad[0] = pdev; +			break; +		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD1: +			pvt->pci_tad[1] = pdev; +			break; +		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD2: +			if (!mode_2ha) +				pvt->pci_tad[2] = pdev; +			break; +		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3: +			if (!mode_2ha) +				pvt->pci_tad[3] = pdev; +			break; +		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0: +			pvt->pci_ddrio = pdev; +			break; +		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1: +			pvt->pci_ha1 = pdev; +			break; +		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA: +			pvt->pci_ha1_ta = pdev; +			break; +		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD0: +			if (mode_2ha) +				pvt->pci_tad[2] = pdev; +			break; +		case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD1: +			if (mode_2ha) +				pvt->pci_tad[3] = pdev; +			break; +		default: +			break; +		} + +		edac_dbg(0, "Associated PCI %02x.%02d.%d with dev = %p\n", +			 sbridge_dev->bus, +			 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), +			 pdev); +	} + +	/* Check if everything were registered */ +	if (!pvt->pci_sad0 || !pvt->pci_ha0 || !pvt->pci_sad1 || +	    !pvt->pci_ras  || !pvt->pci_ta || !pvt->info.pci_vtd) +		goto enodev; + +	for (i = 0; i < NUM_CHANNELS; i++) { +		if (!pvt->pci_tad[i]) +			goto enodev; +	} +	return 0; + +enodev: +	sbridge_printk(KERN_ERR, "Some needed devices are missing\n"); +	return -ENODEV; +} +  /****************************************************************************  			Error check routines   ****************************************************************************/ @@ -1736,6 +1974,9 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,  	 * EDAC core should be handling the channel mask, in order to point  	 * to the group of dimm's where the error may be happening.  	 */ +	if (!pvt->is_lockstep && !pvt->is_mirrored && !pvt->is_close_pg) +		channel = first_channel; +  	snprintf(msg, sizeof(msg),  		 "%s%s area:%s err_code:%04x:%04x socket:%d channel_mask:%ld rank:%d",  		 overflow ? " OVERFLOW" : "", @@ -1865,10 +2106,6 @@ static int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val,  			  "%u APIC %x\n", mce->cpuvendor, mce->cpuid,  			  mce->time, mce->socketid, mce->apicid); -	/* Only handle if it is the right mc controller */ -	if (cpu_data(mce->cpu).phys_proc_id != pvt->sbridge_dev->mc) -		return NOTIFY_DONE; -  	smp_rmb();  	if ((pvt->mce_out + 1) % MCE_LOG_LEN == pvt->mce_in) {  		smp_wmb(); @@ -1932,7 +2169,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)  	int rc;  	/* Check the number of active and not disabled channels */ -	rc = check_if_ecc_is_active(sbridge_dev->bus); +	rc = check_if_ecc_is_active(sbridge_dev->bus, type);  	if (unlikely(rc < 0))  		return rc; @@ -1971,11 +2208,15 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)  	mci->edac_check = sbridge_check_error;  	pvt->info.type = type; -	if (type == IVY_BRIDGE) { +	switch (type) { +	case IVY_BRIDGE:  		pvt->info.rankcfgr = IB_RANK_CFG_A;  		pvt->info.get_tolm = ibridge_get_tolm;  		pvt->info.get_tohm = ibridge_get_tohm;  		pvt->info.dram_rule = ibridge_dram_rule; +		pvt->info.get_memory_type = get_memory_type; +		pvt->info.get_node_id = get_node_id; +		pvt->info.rir_limit = rir_limit;  		pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule);  		pvt->info.interleave_list = ibridge_interleave_list;  		pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); @@ -1986,11 +2227,15 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)  		rc = ibridge_mci_bind_devs(mci, sbridge_dev);  		if (unlikely(rc < 0))  			goto fail0; -	} else { +		break; +	case SANDY_BRIDGE:  		pvt->info.rankcfgr = SB_RANK_CFG_A;  		pvt->info.get_tolm = sbridge_get_tolm;  		pvt->info.get_tohm = sbridge_get_tohm;  		pvt->info.dram_rule = sbridge_dram_rule; +		pvt->info.get_memory_type = get_memory_type; +		pvt->info.get_node_id = get_node_id; +		pvt->info.rir_limit = rir_limit;  		pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule);  		pvt->info.interleave_list = sbridge_interleave_list;  		pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list); @@ -2001,8 +2246,27 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)  		rc = sbridge_mci_bind_devs(mci, sbridge_dev);  		if (unlikely(rc < 0))  			goto fail0; -	} +		break; +	case HASWELL: +		/* rankcfgr isn't used */ +		pvt->info.get_tolm = haswell_get_tolm; +		pvt->info.get_tohm = haswell_get_tohm; +		pvt->info.dram_rule = ibridge_dram_rule; +		pvt->info.get_memory_type = haswell_get_memory_type; +		pvt->info.get_node_id = haswell_get_node_id; +		pvt->info.rir_limit = haswell_rir_limit; +		pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule); +		pvt->info.interleave_list = ibridge_interleave_list; +		pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); +		pvt->info.interleave_pkg = ibridge_interleave_pkg; +		mci->ctl_name = kasprintf(GFP_KERNEL, "Haswell Socket#%d", mci->mc_idx); +		/* Store pci devices at mci for faster access */ +		rc = haswell_mci_bind_devs(mci, sbridge_dev); +		if (unlikely(rc < 0)) +			goto fail0; +		break; +	}  	/* Get dimm basic config and the memory layout */  	get_dimm_config(mci); @@ -2037,10 +2301,10 @@ fail0:  static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)  { -	int rc; +	int rc = -ENODEV;  	u8 mc, num_mc = 0;  	struct sbridge_dev *sbridge_dev; -	enum type type; +	enum type type = SANDY_BRIDGE;  	/* get the pci devices we want to reserve for our use */  	mutex_lock(&sbridge_edac_lock); @@ -2054,12 +2318,19 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)  	}  	probed++; -	if (pdev->device == PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA) { +	switch (pdev->device) { +	case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA:  		rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_ibridge_table);  		type = IVY_BRIDGE; -	} else { +		break; +	case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA:  		rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_sbridge_table);  		type = SANDY_BRIDGE; +		break; +	case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0: +		rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_haswell_table); +		type = HASWELL; +		break;  	}  	if (unlikely(rc < 0))  		goto fail0; @@ -2068,6 +2339,7 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)  	list_for_each_entry(sbridge_dev, &sbridge_edac_list, list) {  		edac_dbg(0, "Registering MC#%d (%d of %d)\n",  			 mc, mc + 1, num_mc); +  		sbridge_dev->mc = mc++;  		rc = sbridge_register_mci(sbridge_dev, type);  		if (unlikely(rc < 0))  | 
