mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	sb_edac: Add support for Broadwell-DE processor
Broadwell-DE is the microserver version of next generation Xeon processors. A whole bunch of new PCIe device ids, but otherwise pretty much the same as Haswell. Acked-by: Aristeu Rozanski <aris@redhat.com> Signed-off-by: Tony Luck <tony.luck@intel.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
This commit is contained in:
		
							parent
							
								
									f7cf2a22a2
								
							
						
					
					
						commit
						1f39581a9a
					
				
					 1 changed files with 157 additions and 6 deletions
				
			
		| 
						 | 
				
			
			@ -262,6 +262,7 @@ enum type {
 | 
			
		|||
	SANDY_BRIDGE,
 | 
			
		||||
	IVY_BRIDGE,
 | 
			
		||||
	HASWELL,
 | 
			
		||||
	BROADWELL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct sbridge_pvt;
 | 
			
		||||
| 
						 | 
				
			
			@ -446,7 +447,7 @@ static const struct pci_id_table pci_dev_descr_ibridge_table[] = {
 | 
			
		|||
 *	- 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_DDRCRCLKCONTROLS 0xa10 /* Ditto on Broadwell */
 | 
			
		||||
#define HASWELL_HASYSDEFEATURE2 0x84
 | 
			
		||||
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_VTD_MISC 0x2f28
 | 
			
		||||
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0	0x2fa0
 | 
			
		||||
| 
						 | 
				
			
			@ -497,6 +498,46 @@ static const struct pci_id_table pci_dev_descr_haswell_table[] = {
 | 
			
		|||
	{0,}			/* 0 terminated list. */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Broadwell support
 | 
			
		||||
 *
 | 
			
		||||
 * DE processor:
 | 
			
		||||
 *	- 1 IMC
 | 
			
		||||
 *	- 2 DDR3 channels, 2 DPC per channel
 | 
			
		||||
 */
 | 
			
		||||
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_VTD_MISC 0x6f28
 | 
			
		||||
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0	0x6fa0
 | 
			
		||||
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA	0x6fa8
 | 
			
		||||
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_THERMAL 0x6f71
 | 
			
		||||
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD0 0x6ffc
 | 
			
		||||
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD1 0x6ffd
 | 
			
		||||
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD0 0x6faa
 | 
			
		||||
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD1 0x6fab
 | 
			
		||||
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD2 0x6fac
 | 
			
		||||
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD3 0x6fad
 | 
			
		||||
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_DDRIO0 0x6faf
 | 
			
		||||
 | 
			
		||||
static const struct pci_id_descr pci_dev_descr_broadwell[] = {
 | 
			
		||||
	/* first item must be the HA */
 | 
			
		||||
	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0, 0)		},
 | 
			
		||||
 | 
			
		||||
	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD0, 0)	},
 | 
			
		||||
	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD1, 0)	},
 | 
			
		||||
 | 
			
		||||
	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA, 0)	},
 | 
			
		||||
	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_THERMAL, 0)	},
 | 
			
		||||
	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD0, 0)	},
 | 
			
		||||
	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD1, 0)	},
 | 
			
		||||
	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD2, 0)	},
 | 
			
		||||
	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD3, 0)	},
 | 
			
		||||
	{ PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_DDRIO0, 1)	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct pci_id_table pci_dev_descr_broadwell_table[] = {
 | 
			
		||||
	PCI_ID_TABLE_ENTRY(pci_dev_descr_broadwell),
 | 
			
		||||
	{0,}			/* 0 terminated list. */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *	pci_device_id	table for which devices we are looking for
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -504,6 +545,7 @@ static const struct pci_device_id sbridge_pci_tbl[] = {
 | 
			
		|||
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0)},
 | 
			
		||||
	{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)},
 | 
			
		||||
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0)},
 | 
			
		||||
	{0,}			/* 0 terminated list. */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -768,12 +810,22 @@ static int check_if_ecc_is_active(const u8 bus, enum type type)
 | 
			
		|||
	struct pci_dev *pdev = NULL;
 | 
			
		||||
	u32 mcmtr, id;
 | 
			
		||||
 | 
			
		||||
	if (type == IVY_BRIDGE)
 | 
			
		||||
	switch (type) {
 | 
			
		||||
	case IVY_BRIDGE:
 | 
			
		||||
		id = PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA;
 | 
			
		||||
	else if (type == HASWELL)
 | 
			
		||||
		break;
 | 
			
		||||
	case HASWELL:
 | 
			
		||||
		id = PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA;
 | 
			
		||||
	else
 | 
			
		||||
		break;
 | 
			
		||||
	case SANDY_BRIDGE:
 | 
			
		||||
		id = PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA;
 | 
			
		||||
		break;
 | 
			
		||||
	case BROADWELL:
 | 
			
		||||
		id = PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pdev = get_pdev_same_bus(bus, id);
 | 
			
		||||
	if (!pdev) {
 | 
			
		||||
| 
						 | 
				
			
			@ -801,7 +853,7 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 | 
			
		|||
	enum edac_type mode;
 | 
			
		||||
	enum mem_type mtype;
 | 
			
		||||
 | 
			
		||||
	if (pvt->info.type == HASWELL)
 | 
			
		||||
	if (pvt->info.type == HASWELL || pvt->info.type == BROADWELL)
 | 
			
		||||
		pci_read_config_dword(pvt->pci_sad1, SAD_TARGET, ®);
 | 
			
		||||
	else
 | 
			
		||||
		pci_read_config_dword(pvt->pci_br0, SAD_TARGET, ®);
 | 
			
		||||
| 
						 | 
				
			
			@ -1182,7 +1234,7 @@ 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) {
 | 
			
		||||
	} else if (pvt->info.type == HASWELL || pvt->info.type == BROADWELL) {
 | 
			
		||||
		int bits, a7mode = A7MODE(dram_rule);
 | 
			
		||||
 | 
			
		||||
		if (a7mode) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1831,6 +1883,82 @@ static int haswell_mci_bind_devs(struct mem_ctl_info *mci,
 | 
			
		|||
	return -ENODEV;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int broadwell_mci_bind_devs(struct mem_ctl_info *mci,
 | 
			
		||||
				 struct sbridge_dev *sbridge_dev)
 | 
			
		||||
{
 | 
			
		||||
	struct sbridge_pvt *pvt = mci->pvt_info;
 | 
			
		||||
	struct pci_dev *pdev;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	/* 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_BROADWELL_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_BROADWELL_IMC_CBO_SAD0:
 | 
			
		||||
			pvt->pci_sad0 = pdev;
 | 
			
		||||
			break;
 | 
			
		||||
		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD1:
 | 
			
		||||
			pvt->pci_sad1 = pdev;
 | 
			
		||||
			break;
 | 
			
		||||
		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0:
 | 
			
		||||
			pvt->pci_ha0 = pdev;
 | 
			
		||||
			break;
 | 
			
		||||
		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA:
 | 
			
		||||
			pvt->pci_ta = pdev;
 | 
			
		||||
			break;
 | 
			
		||||
		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_THERMAL:
 | 
			
		||||
			pvt->pci_ras = pdev;
 | 
			
		||||
			break;
 | 
			
		||||
		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD0:
 | 
			
		||||
			pvt->pci_tad[0] = pdev;
 | 
			
		||||
			break;
 | 
			
		||||
		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD1:
 | 
			
		||||
			pvt->pci_tad[1] = pdev;
 | 
			
		||||
			break;
 | 
			
		||||
		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD2:
 | 
			
		||||
			pvt->pci_tad[2] = pdev;
 | 
			
		||||
			break;
 | 
			
		||||
		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD3:
 | 
			
		||||
			pvt->pci_tad[3] = pdev;
 | 
			
		||||
			break;
 | 
			
		||||
		case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_DDRIO0:
 | 
			
		||||
			pvt->pci_ddrio = 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
 | 
			
		||||
 ****************************************************************************/
 | 
			
		||||
| 
						 | 
				
			
			@ -2243,6 +2371,25 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
 | 
			
		|||
		if (unlikely(rc < 0))
 | 
			
		||||
			goto fail0;
 | 
			
		||||
		break;
 | 
			
		||||
	case BROADWELL:
 | 
			
		||||
		/* 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, "Broadwell Socket#%d", mci->mc_idx);
 | 
			
		||||
 | 
			
		||||
		/* Store pci devices at mci for faster access */
 | 
			
		||||
		rc = broadwell_mci_bind_devs(mci, sbridge_dev);
 | 
			
		||||
		if (unlikely(rc < 0))
 | 
			
		||||
			goto fail0;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Get dimm basic config and the memory layout */
 | 
			
		||||
| 
						 | 
				
			
			@ -2308,6 +2455,10 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 | 
			
		|||
		rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_haswell_table);
 | 
			
		||||
		type = HASWELL;
 | 
			
		||||
		break;
 | 
			
		||||
	case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0:
 | 
			
		||||
		rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_broadwell_table);
 | 
			
		||||
		type = BROADWELL;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	if (unlikely(rc < 0))
 | 
			
		||||
		goto fail0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue